Skip to content
tezvyn:
Menu

Swift Library Evolution: Shipping Break-Proof Frameworks

Source: github.comHardHow cards are made

Library Evolution lets you update a Swift framework without breaking apps that use it, even if they don't recompile. It's crucial for shipping binary SDKs. The footgun is that many seemingly safe changes, like adding a struct property, are binary-breaking by…

Why it exists

Before Swift 5, changing a public type in a compiled framework (like adding a property to a struct) was a breaking change. Every app using that framework had to recompile with the new version to avoid crashes. Library Evolution was created to allow frameworks to evolve independently of the apps that use them, eliminating this fragile dependency.

The mental model

Think of your compiled framework as a service with a public contract, its Application Binary Interface (ABI). Library Evolution defines the rules for changing the implementation behind that contract without breaking existing clients. It's about promising a certain layout and behavior, and using Swift features to either preserve flexibility for future changes or lock down the contract for performance.

How it works

By default, Swift enables "resilience" when Library Evolution is on. This means the compiler adds a layer of indirection for accessing things like struct properties or enum cases. This indirection allows the library to change its internal memory layout without affecting the client binary, which looks up the layout at runtime. For performance, you can trade this flexibility away by marking types as @frozen. A frozen type's layout is fixed and becomes part of the public ABI, so it cannot be changed later without breaking clients. Similarly, @inlinable functions copy their code into the client, locking their implementation permanently.

When to use it

You must enable Library Evolution mode when compiling any framework you intend to distribute as a binary (.framework or .xcframework) to third parties. It is the standard for SDKs, system frameworks, and any shared library where you don't control all the clients and their recompilation schedules.

When not to use it

You don't need it if you control all the targets that link against your library, such as in a monolithic app with multiple internal modules. In that case, the entire app is compiled together, so breaking binary compatibility between modules isn't an issue. Enabling it adds a small performance overhead due to the runtime indirections.

One canonical example

A library ships a public struct: public struct UserInfo { public var id: String }. An app is built using this. Later, the library author adds a new property: public struct UserInfo { public var id: String; public var name: String }. Without library evolution, the old app binary, which expects the struct to have a certain size, would crash. With library evolution, Swift uses runtime metadata to access properties by name, not by a fixed offset. The old app continues to work with the new library; it just can't see or use the new name property.

Interview question

What is the primary trade-off when marking a Swift type as @frozen or a function as @inlinable within a framework using Library Evolution?

  • a.Greater flexibility for the framework's internal evolution, but with a slight increase in the client application's launch time.
  • b.Reduced framework binary size, but requiring clients to recompile with every framework update.
  • c.Increased runtime performance for clients, but at the cost of making future changes to the type's or function's implementation binary-breaking.Correct
  • d.Enhanced compile-time safety checks, but introducing a small overhead in the framework's build process.
Why?

The card states that @frozen and @inlinable are used "For performance, you can trade this flexibility away." This means they provide performance benefits by fixing the ABI, which then makes future changes to that type or function binary-breaking. Option A is incorrect because these features reduce flexibility, rather than increasing it.

Just read this? Test yourself on what you have been reading.

Read the original → github.com

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on swift — each one lists the topics its interview covers.

See open roles