0.21.0
A minor release on top of 0.20.0. interface now prints the class members that a stripped OS framework no longer names β 53 of them across AppKit β lists class methods in vtable order, and marks Swift classes renamed for the Objective-C runtime with @objc(Name). ABI snapshots move to format version 6, so regenerate baselines saved by 0.20.0.
What's new
- Class members named only by their method descriptor are recovered. In an image stripped of its local symbols (AppKit in the OS dyld shared cache), a public class method's implementation has no name left, and
interfacedropped it:NSTableViewDiffableDataSourceandNSCollectionViewDiffableDataSourceprinted onlyinitanddeinit. These members are now read from the class's vtable, anddiff,evolutionand snapshots see them too. - Class members print in vtable order.
interfacelists a class's vtable methods first, in slot order β the source's declaration order, the waydumpalready walks them β then the remaining members by category as before. A slot nothing names is skipped.--sort-members-by-offsetand thediff/evolutioninterfaces are unchanged. @objc(Name)on renamed classes. A Swift class whose source gave the Objective-C runtime its own name (@objc(NSScrollPocket)) prints that attribute ininterface,dumpand thediff/evolutionheaders, or@_objcRuntimeName(Name)where the class uses Swift's native object model and@objcwould not compile. macOS 27's AppKit has 74 such classes.
Fixes
- A renamed class lost every recovered
@objcandoverrideon its members, and in a stripped image its Objective-C members printed asfinal. With an Objective-C superclass, its static field offsets could be a few bytes off. init/init?was decided by the first closure in the signature:NSCollectionViewDiffableDataSource.init(collectionView:itemProvider:)printed asinit?because its item provider returns an optional, and SwiftUI's failableCoreDisplayLink.init?(displayID:handler:)printed asinit.- Reading an in-process image that is not in the dyld shared cache but was loaded above the shared region's start printed wrong member and IMP addresses. Fixed by MachOKitExtensions
0.1.2.
Breaking
- The library no longer empties its per-image caches under memory pressure. A host that relied on that calls
SharedCacheRegistry.shared.evictImagesWithoutLiveOwners()(@_spi(Internals) import MachOCaches) when it wants memory back; it evicts every image no liveSwiftDeclarationIndexerstill owns. SharedCache(SPIInternals) isfinaland built by composition:final class Foo: SharedCache<Storage> { override func buildStorage(for:) β¦ }becomesfinal class Foo { private let cache = SharedCache<Storage>(evictionGroup: β¦) }, looked up withcache.storage(in: machO) { build($0) }.init(),buildStorage(for:),buildStorage(),storage(),contains()andremove()are removed.SymbolIndexStoreandInternedNodeReferenceCacheare no longer its subclasses; their instance API is unchanged.
Compatibility
- ABI snapshot
formatVersion5 β 6. A snapshot saved by0.20.0is rejected with a format-version error rather than misreporting the recovered members as added; regenerate it with0.21.0. The key scheme is unchanged. - Rendered output changes only where listed above: class member order in single-version
interface, the recovered members,@objc(Name)and the renamed classes' members, and theinit/init?corrections. - Dependency floors: MachOKitExtensions
0.1.2(was0.1.1), swift-capstone6.0.1 ..< 7.0.0(was6.0.0;6.0.1restores the AArch64 backend for packages still spelling the pre-v6 trait). All other pins are unchanged from0.20.0. - The command line is unchanged: no flag was added, removed or given a new default.
Requirements
- Swift 6.2+
- Xcode 26.0+
Full design: evolution proposals 0052β0054; implementation notes DescriptorOnlyVTableMembers.md, CustomObjCClassNames.md and Modules/MachOCaches.md.