A Deep Dive into Apple’s Toolbox: How to Explore First-Party Frameworks

When analyzing your project, Sw!ftalyzer shows you which frameworks you are using. This includes 3rd party frameworks as well as standard frameworks from Apple. In addition, you can see all connections from your entities to those entities defined in these frameworks. But how does Sw!ftalyzer know which entities belong to which of Apples frameworks? In this article we’ll show you where this information is coming from and how you can get this data yourself.

Finding Framework Definitions

 
Apples frameworks are buried deep in Xcode. You can find them at 

pathToXcode/Contents/Developer/Platforms/<platform_identifier>.platform/Developer/SDKs/<platform_identifier>.sdk/System/Library/Frameworks


with <platform_identifier> being either

  • iPhoneSimulator for frameworks available to iOS,
  • MacOSX for those used on macOS,
  • AppleTVOS for Apple TV or
  • WatchOS for WatchOS apps 

There are two different formats we can look at to find the entities a framework exports: tbd files and swiftinterface files. 

tbd stands for Text-Based Stub Library and they contain symbols and meta information of a dynamic library needed for linking these libraries during the compilation process. They are human readable Yaml files.

swiftinterface contain the interface of a Swift module. They encapsulate the public interface of Swift modules, showcasing the accessible entities like classes, structs and more, excluding implementation details. These files, generated during the Swift compilation process, serve as references for external modules and define what parts of the module are available. Starting from the file path above, you need to append 

Modules/<framework_name>.swiftmodule/arm64-apple-<platform>.swiftinterface


with <framework_name> being the name of the framework and <platform> being either ios-simulator, macos, tvos-simulator or watchos.

Parsing Framework Definitions


tbd files are Yaml files, so they can be parsed with a framework like Yams. They have various fields to explore, here’s a short excerpt of the tbd file for the CoreAudio framework: 

--- !tapi-tbd
tbd-version:     4
targets:         [ i386-ios-simulator, x86_64-ios-simulator, arm64-ios-simulator ]
uuids:
  - target:          i386-ios-simulator
    value:           ED57F217-F2A3-337C-9DF5-309C7C0270FD
  - target:          x86_64-ios-simulator
    value:           ADB66301-4A89-309B-8419-1017901C5C04
  - target:          arm64-ios-simulator
    value:           E97F0D76-5FC2-3501-9E2B-093F4D9EE9D4
install-name:    '/System/Library/Frameworks/CoreAudio.framework/CoreAudio'
exports:
  - targets:         [ i386-ios-simulator, x86_64-ios-simulator, arm64-ios-simulator ]
    objc-classes:    [ CAActiveDeviceStreamsForProcess, CAProcessDevicePair, CATapDescription ]
...


The relevant information is the list of classes exported by the framework labeled objc-classes.

swiftinterface files are basically Swift files and thus can be parsed programmatically with SwiftSyntax, Apples framework for creating, inspecting and manipulating the syntax tree for Swift code.

Here’s how a short part of the swiftinterface file for SwiftUI looks like:

// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7.1 (swiftlang-5.7.1.134.3 clang-1400.0.29.51)
// swift-module-flags: -target arm64-apple-ios16.2-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Osize -library-level api -library-level api -module-name SwiftUI
// swift-module-flags-ignorable: -enable-bare-slash-regex -user-module-version 4.2.11
// …
import Foundation
import OSLog
import Swift
@_exported import SwiftUI
import UIKit
// …
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public struct Button<Label> : SwiftUI.View where Label : SwiftUI.View {
  public init(action: @escaping () -> Swift.Void, @SwiftUI.ViewBuilder label: () -> Label)
  @_Concurrency.MainActor(unsafe) public var body: some SwiftUI.View {
    get
  }
  public typealias Body = @_opaqueReturnTypeOf("$s7SwiftUI6ButtonV4bodyQrvp", 0) __<Label>
}


It starts with meta information followed by imports of other frameworks. After that, everything that’s available in SwiftUI is listed. To find all these framework entities, a class implementing the SyntaxVisitor protocol can visit all nodes defined in the swiftinterface file and can extract all declarations of public code entities like protocol, enum, struct and class.

Frameworks and Sw!ftalyzer


Version 0.41.0 of Sw!ftalyzer (released December 2023) included an overhaul of how frameworks are handled. With a new CLI tool that processes framework information based on latest versions of Apples standard frameworks, the number of frameworks automatically recognised by Sw!ftalyzer increased from about 20 to about 200. This provides a more detailed analysis with less manual work needed.

In addition to that frameworks are no longer found by looking through all framework entities but instead by including imports into the analysis. Only those frameworks are checked that are actually imported and used by your source code files, allowing for a faster and more precise analysis of your project.