mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
114 lines
5.1 KiB
Markdown
114 lines
5.1 KiB
Markdown
# 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?
|