|
| 1 | +# Objective-C and Swift Interop |
| 2 | + |
| 3 | +This document describes how Swift interoperates with Objective-C code and the |
| 4 | +Objective-C runtime. |
| 5 | + |
| 6 | +Interactions between the Swift runtime and the Objective-C runtime are |
| 7 | +implementation details that are subject to change! Don't write code outside the |
| 8 | +Swift runtime that relies on these details. |
| 9 | + |
| 10 | +This document only applies on platforms where Objective-C interop is available. |
| 11 | +On other platforms, Swift omits everything related to Objective-C. |
| 12 | + |
| 13 | +## Messaging |
| 14 | + |
| 15 | +Swift generates calls to `objc_msgSend` and variants to send an Objective-C |
| 16 | +message, just like an Objective-C compiler does. Swift methods marked or |
| 17 | +inferred as `@objc` are exposed as entries in the Objective-C method list for |
| 18 | +the class. |
| 19 | + |
| 20 | +## Classes |
| 21 | + |
| 22 | +All Swift classes are also Objective-C classes. When Swift classes inherit from |
| 23 | +an Objective-C class, they inherit in exactly the same way an Objective-C class |
| 24 | +would, by generating an Objective-C class structure whose `superclass` field |
| 25 | +points to the Objective-C superclass. Pure Swift classes with no superclass |
| 26 | +generate an Objective-C class that subclasses the internal `SwiftObject` class |
| 27 | +in the runtime. `SwiftObject` implements a minimal interface allowing these |
| 28 | +objects to be passed around through Objective-C code with correct memory |
| 29 | +management and basic functionality. |
| 30 | + |
| 31 | +### Compiler-Generated Classes |
| 32 | + |
| 33 | +Swift classes can be generated as part of the binary's static data, like a |
| 34 | +normal Objective-C class would be. The compiler lays down a structure matching |
| 35 | +the Objective-C class structure, followed by additional Swift-specific fields. |
| 36 | + |
| 37 | +### Dynamically-Generated Classes |
| 38 | + |
| 39 | +Some Swift classes (for example, generic classes) must be generated at runtime. |
| 40 | +For these classes, the Swift runtime allocates space using `MetadataAllocator`, |
| 41 | +fills it out with the appropriate class structures, and then registers the new |
| 42 | +class with the Objective-C runtime by using the SPI `objc_readClassPair`. |
| 43 | + |
| 44 | +### Stub Classes |
| 45 | + |
| 46 | +Note: stub classes are only supported on macOS 10.15+, iOS/tvOS 13+, and watchOS |
| 47 | +6+. The Objective-C runtime on older OSes does not have the necessary calls to |
| 48 | +support them. The Swift compiler will only emit stub classes when targeting an |
| 49 | +OS version that supports them. |
| 50 | + |
| 51 | +Stub classes can be generated for dynamically-generated classes that are known |
| 52 | +at compile time but whose size can't be known until runtime. This unknown size |
| 53 | +means that they can't be laid down statically by the compiler, since the |
| 54 | +compiler wouldn't know how much space to reserve. Instead, the compiler |
| 55 | +generates a *stub class*. A stub class consists of: |
| 56 | + |
| 57 | + uintptr_t dummy; |
| 58 | + uintptr_t one; |
| 59 | + SwiftMetadataInitializer initializer; |
| 60 | + |
| 61 | +The `dummy` field exists to placate the linker. The symbol for the stub class |
| 62 | +points at the `one` field, and uses the `.alt_entry` directive to indicate that |
| 63 | +it is associated with the `dummy` field. |
| 64 | + |
| 65 | +The `one` field exists where a normal class's `isa` field would be. The |
| 66 | +Objective-C runtime uses this field to distinguish between stub classes and |
| 67 | +normal classes. Values between 1 and 15, inclusive, indicate a stub class. |
| 68 | +Values other than 1 are currently reserved. |
| 69 | + |
| 70 | +An Objective-C compiler can refer to these classes from Objective-C code. A |
| 71 | +reference to a stub class must go through a `classref`, which is a pointer to a |
| 72 | +class pointer. The low bit of the class pointer in the `classref` indicates |
| 73 | +whether it needs to be initialized. When the low bit is set, the Objective-C |
| 74 | +runtime treats it as a pointer to a stub class and uses the initializer function |
| 75 | +to retrieve the real class. When the low bit is clear, the Objective-C runtime |
| 76 | +treats it as a pointer to a real class and does nothing. |
| 77 | + |
| 78 | +The compiler must then access the class by generating a call to |
| 79 | +the Objective-C runtime function `objc_loadClassref` which returns the |
| 80 | +initialized and relocated class. For example, this code: |
| 81 | + |
| 82 | + [SwiftStubClass class] |
| 83 | + |
| 84 | +Generates something like this code: |
| 85 | + |
| 86 | + static Class *SwiftStubClassRef = |
| 87 | + (uintptr_t *)&_OBJC_CLASS_$_SwiftStubClassRef + 1; |
| 88 | + Class SwiftStubClass = objc_loadClassref(&SwiftStubClassRef); |
| 89 | + objc_msgSend(SwiftStubClass, @selector(class)); |
| 90 | + |
| 91 | +The initializer function is responsible for setting up the new class and |
| 92 | +returning it to the Objective-C runtime. It must be idempotent: the Objective-C |
| 93 | +runtime takes no precautions to avoid calling the initializer multiple times in |
| 94 | +a multithreaded environment, and expects the initializer function itself to take |
| 95 | +care of any such needs. |
| 96 | + |
| 97 | +The initializer function must register the newly created class by calling the |
| 98 | +`_objc_realizeClassFromSwift` SPI in the Objective-C runtime. It must pass the |
| 99 | +new class and the stub class. The Objective-C runtime uses this information to |
| 100 | +set up a mapping from the stub class to the real class. This mapping allows |
| 101 | +Objective-C categories on stub classes to work: when a stub class is realized |
| 102 | +from Swift, any categories associated with the stub class are added to the |
| 103 | +corresponding real class. |
| 104 | + |
| 105 | +## To Document |
| 106 | + |
| 107 | +This document is incomplete. It should be expanded to include: |
| 108 | + |
| 109 | +- Information about the ABI of ObjC and Swift class structures. |
| 110 | +- The is-Swift bit. |
| 111 | +- Legacy versus stable ABI and is-Swift bit rewriting. |
| 112 | +- Objective-C runtime hooks used by the Swift runtime. |
| 113 | +- And more? |
0 commit comments