mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Docs] Start writing some docs about ObjC interop.
This commit is contained in:
113
docs/ObjCInterop.md
Normal file
113
docs/ObjCInterop.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Objective-C and Swift Interop
|
||||
|
||||
This document describes how Swift interoperates with Objective-C code and the
|
||||
Objective-C runtime.
|
||||
|
||||
Interactions between the Swift runtime and the Objective-C runtime are
|
||||
implementation details that are subject to change! Don't write code outside the
|
||||
Swift runtime that relies on these details.
|
||||
|
||||
This document only applies on platforms where Objective-C interop is available.
|
||||
On other platforms, Swift omits everything related to Objective-C.
|
||||
|
||||
## Messaging
|
||||
|
||||
Swift generates calls to `objc_msgSend` and variants to send an Objective-C
|
||||
message, just like an Objective-C compiler does. Swift methods marked or
|
||||
inferred as `@objc` are exposed as entries in the Objective-C method list for
|
||||
the class.
|
||||
|
||||
## Classes
|
||||
|
||||
All Swift classes are also Objective-C classes. When Swift classes inherit from
|
||||
an Objective-C class, they inherit in exactly the same way an Objective-C class
|
||||
would, by generating an Objective-C class structure whose `superclass` field
|
||||
points to the Objective-C superclass. Pure Swift classes with no superclass
|
||||
generate an Objective-C class that subclasses the internal `SwiftObject` class
|
||||
in the runtime. `SwiftObject` implements a minimal interface allowing these
|
||||
objects to be passed around through Objective-C code with correct memory
|
||||
management and basic functionality.
|
||||
|
||||
### Compiler-Generated Classes
|
||||
|
||||
Swift classes can be generated as part of the binary's static data, like a
|
||||
normal Objective-C class would be. The compiler lays down a structure matching
|
||||
the Objective-C class structure, followed by additional Swift-specific fields.
|
||||
|
||||
### Dynamically-Generated Classes
|
||||
|
||||
Some Swift classes (for example, generic classes) must be generated at runtime.
|
||||
For these classes, the Swift runtime allocates space using `MetadataAllocator`,
|
||||
fills it out with the appropriate class structures, and then registers the new
|
||||
class with the Objective-C runtime by using the SPI `objc_readClassPair`.
|
||||
|
||||
### Stub Classes
|
||||
|
||||
Note: stub classes are only supported on macOS 10.15+, iOS/tvOS 13+, and watchOS
|
||||
6+. The Objective-C runtime on older OSes does not have the necessary calls to
|
||||
support them. The Swift compiler will only emit stub classes when targeting an
|
||||
OS version that supports them.
|
||||
|
||||
Stub classes can be generated for dynamically-generated classes that are known
|
||||
at compile time but whose size can't be known until runtime. This unknown size
|
||||
means that they can't be laid down statically by the compiler, since the
|
||||
compiler wouldn't know how much space to reserve. Instead, the compiler
|
||||
generates a *stub class*. A stub class consists of:
|
||||
|
||||
uintptr_t dummy;
|
||||
uintptr_t one;
|
||||
SwiftMetadataInitializer initializer;
|
||||
|
||||
The `dummy` field exists to placate the linker. The symbol for the stub class
|
||||
points at the `one` field, and uses the `.alt_entry` directive to indicate that
|
||||
it is associated with the `dummy` field.
|
||||
|
||||
The `one` field exists where a normal class's `isa` field would be. The
|
||||
Objective-C runtime uses this field to distinguish between stub classes and
|
||||
normal classes. Values between 1 and 15, inclusive, indicate a stub class.
|
||||
Values other than 1 are currently reserved.
|
||||
|
||||
An Objective-C compiler can refer to these classes from Objective-C code. A
|
||||
reference to a stub class must go through a `classref`, which is a pointer to a
|
||||
class pointer. The low bit of the class pointer in the `classref` indicates
|
||||
whether it needs to be initialized. When the low bit is set, the Objective-C
|
||||
runtime treats it as a pointer to a stub class and uses the initializer function
|
||||
to retrieve the real class. When the low bit is clear, the Objective-C runtime
|
||||
treats it as a pointer to a real class and does nothing.
|
||||
|
||||
The compiler must then access the class by generating a call to
|
||||
the Objective-C runtime function `objc_loadClassref` which returns the
|
||||
initialized and relocated class. For example, this code:
|
||||
|
||||
[SwiftStubClass class]
|
||||
|
||||
Generates something like this code:
|
||||
|
||||
static Class *SwiftStubClassRef =
|
||||
(uintptr_t *)&_OBJC_CLASS_$_SwiftStubClassRef + 1;
|
||||
Class SwiftStubClass = objc_loadClassref(&SwiftStubClassRef);
|
||||
objc_msgSend(SwiftStubClass, @selector(class));
|
||||
|
||||
The initializer function is responsible for setting up the new class and
|
||||
returning it to the Objective-C runtime. It must be idempotent: the Objective-C
|
||||
runtime takes no precautions to avoid calling the initializer multiple times in
|
||||
a multithreaded environment, and expects the initializer function itself to take
|
||||
care of any such needs.
|
||||
|
||||
The initializer function must register the newly created class by calling the
|
||||
`_objc_realizeClassFromSwift` SPI in the Objective-C runtime. It must pass the
|
||||
new class and the stub class. The Objective-C runtime uses this information to
|
||||
set up a mapping from the stub class to the real class. This mapping allows
|
||||
Objective-C categories on stub classes to work: when a stub class is realized
|
||||
from Swift, any categories associated with the stub class are added to the
|
||||
corresponding real class.
|
||||
|
||||
## To Document
|
||||
|
||||
This document is incomplete. It should be expanded to include:
|
||||
|
||||
- Information about the ABI of ObjC and Swift class structures.
|
||||
- The is-Swift bit.
|
||||
- Legacy versus stable ABI and is-Swift bit rewriting.
|
||||
- Objective-C runtime hooks used by the Swift runtime.
|
||||
- And more?
|
||||
Reference in New Issue
Block a user