Compilation phase
class PureSwiftClass {
private var private_var_property = 0
@objc private var objc_private_var_property = 0
var instance_property = 0
@objc let objc_instance_let_property = 0
@objc var objc_instance_var_property = 0
func instance_method(a) {}
@objc func objc_instance_method(a) {}
@objc dynamic func objc_dynamic_instance_method(a){}}Copy the code
Here is the class information generated at compile time:
_$s10TestObjectSwiftClassCN:
struct __objc_class {
_OBJC_METACLASS_$__TtC10TestObjectSwiftClass, // metaclass
_OBJC_CLASS_$_SwiftObject, // superclass
__objc_empty_cache, // cache
0x0, // vtable
__objc_class__TtC10TestObjectSwiftClass_data+1 // data
}
__objc_class__ObjectSwiftClass_data:
struct __objc_data {
0x80, // flags
8,// instance start
48, // instance size
0x0,
0x0, // ivar layout
"ObjectSwiftClass", // name
__objc_class__TtC10TestObjectSwiftClass_methods, // base methods
0x0, // base protocols
__objc_class__TtC10Test6ObjectSwiftClass_ivars, // ivars
0x0, // weak ivar layout
__objc_class__TtC10TestObjectSwiftClass_properties // base properties
}
// methods
__objc_class__ObjectSwiftClass_methods:
struct __objc_method_list {
0x18, // flags
8 // method count
}
struct __objc_method {
"objc_private_instance_var_property", // name
"q16@0:8". // signature -[_TtC10TestObjectSwiftClass objc_private_instance_var_property] // implementation } struct __objc_method {"setObjc_private_var_property:", // name
}
struct __objc_method {
"objc_instance_var_property", // name
}
struct __objc_method {
"setObjc_instance_var_property:", // name
}
struct __objc_method {
"objc_instance_let_property", // name
}
struct __objc_method {
"objc_instance_method", // name
}
struct __objc_method {
"objc_dynamic_instance_method", // name
}
struct __objc_method {
"init", // name
}
// ivars
__objc_class__TtC10TestObjectSwiftClass_ivars:
struct __objc_ivars {
32, // entsize
5 // count
}
struct __objc_ivar {
"private_var_property", // name
}
struct __objc_ivar {
"objc_private_var_property", // name
}
struct __objc_ivar {
"instance_var_property", // name
}
struct __objc_ivar {
"objc_instance_var_property", // name
}
struct __objc_ivar {
"objc_instance_let_property", // name
}
Copy the code
Based on the data generated by the compiler above, you can get some information:
class
Swift
The class compilation phase generates andObjective-C
Same class metadata, that’s why, rightSwift
andObjective-C
They can call each other.
Generic classes do not generate class metadata __objc_class structures, but roData.
class
If a class is not explicitly inherited, it is implicitly inheritedSwiftObject
.
attribute
- All attributes will be added to
class_ro_t
In theivars
Structure, includingprivate
Properties. - use
@objc
Modified properties,var
Property will addset/get
Method,let
Attributes will only be addedget
Methods.
Properties of the Swift class can be modified and obtained using objC-Runtime.
methods
- use
@objc
The decorated methods are added toro_class_t
themethods
In the structure.
Swift structure
ClassMetadata
ClassMetadata is all the ClassMetadata formats in Swift.
struct objc_object {
Class isa;
}
struct objc_class: objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits;
}
struct swift_class_t: objc_class {
uint32_t flags;/ / class
uint32_t instanceAddressOffset;
uint32_t instanceSize;// Object instance size
uint16_t instanceAlignMask;//
uint16_t reserved;// Reserve the field
uint32_t classSize;// Size of the class object
uint32_t classAddressOffset;//
void *description;/ / class description
};
Copy the code
Swift and Objective-C class metadata are shared, and Swift class metadata is just some fields added to Objective-C.
There are also places in the source code where a reinterpret_cast is used directly for interconversion.
Class objcClass = [objcObject class];
ClassMetadata *classAsMetadata = reinterpret_cast<const ClassMetadata *>(objcClass);
Copy the code
HeapObject
In Swift, a class object is really just a pointer to a HeapObject structure. HeapObject consists of HeapMetadata, which is a pointer to class object metadata, and InlineRefCounts, which manages reference counts.
struct HeapObject {
HeapMetadata const *metadata;
InlineRefCounts refCounts;
};
Copy the code
HeapMetadata
andObjective-C
In theisa_t
Structure the same as useISA_MASK
Get the class object.
@interface ObjcClass: NSObject {
}
ObjcClass *objcObject = [ObjcClass new];
HeapObject *heapObject = static_cast<HeapObject *>(objcObject);
ObjcClass *objcObject2 = static_cast<ObjcClass *>(heapObject);
[heapObject retain];
Copy the code
However, since objective-C and Swift reference count management are different, reference count management will be performed in the same way after conversion.
Objective-c and Swift object structure:
Objc {isa_T, instance variables} Swift object {metadata, refCounts, instance variables}Copy the code
Create an object
swift_allocObject
swift_allocObject
The method is used to create aSwift
Object.
void *swift::swift_slowAlloc(size_t size, size_t alignMask) {
void *p;
// This check also forces "default" alignment to use AlignedAlloc.
if (alignMask <= MALLOC_ALIGN_MASK) {
p = malloc(size);
} else {
size_t alignment = (alignMask == ~(size_t(0)))? _swift_MinAllocationAlignment : alignMask +1;
p = AlignedAlloc(size, alignment);
}
if(! p) swift::crash("Could not allocate memory.");
return p;
}
static HeapObject *_swift_allocObject_(HeapMetadata const *metadata,
size_t requiredSize,
size_t requiredAlignmentMask) {
auto object = reinterpret_cast<HeapObject *>(
swift_slowAlloc(requiredSize, requiredAlignmentMask));
// NOTE: this relies on the C++17 guaranteed semantics of no null-pointer
// check on the placement new allocator which we have observed on Windows,
// Linux, and macOS.
new (object) HeapObject(metadata);// Create a new object
return object;
}
Copy the code
- Called after byte alignment based on object size
malloc
Memory is allocated, after which instance variables are initialized. metadata
Represents class object metadata.requiredSize
andrequiredAlignmentMask
Represents object size and byte alignment.
swift_initStackObject
- In some scenarios object creation is optimized by the compiler for
swift_initStackObject
Methods.swift_initStackObject
Create an object on the stack. No reference count consumption and no usemalloc
Memory.
HeapObject *
swift::swift_initStackObject(HeapMetadata const *metadata,
HeapObject *object) {
object->metadata = metadata;
object->refCounts.initForNotFreeing();
return object;
}
Copy the code
Destruction of objects
swift_deallocClassInstance
swift_deallocClassInstance
Used to destroy objects in objectsdealloc
When the call.
void swift::swift_deallocClassInstance(HeapObject *object,
size_t allocatedSize,
size_t allocatedAlignMask) {
#if SWIFT_OBJC_INTEROP
objc_destructInstance((id)object);
#endif
swift_deallocObject(object, allocatedSize, allocatedAlignMask);//
}
Copy the code
- call
objc_destructInstance
Method to release associated objects and weak reference release processing.
Object weak reference of Objc Runtime, not weak reference of Swift environment.
- call
swift_deallocObject
The method callfree
Reclaim memory.
Reference count correlation method
swift_retain
andobjc
Similar to the implementation of reference counting+ 1
.The overflow
Save a portion of the reference count value tosideTable
In the.swift_release
For reference counting- 1
, when the reference count is0
The destroy object method is called.swift_weak
Related methods are used for managementweak
A weak reference.
SwiftObject
In Swift, a class implicitly inherits SwiftObject if it does not explicitly inherit from any other class. SwiftObject implements all methods of the NSObject protocol and some methods of the NSObject class. The main thing is to rewrite part of the method and change the method implementation to swift-related methods.
@interface SwiftObject<NSObject> {
@private
Class isa;
InlineRefCounts refCounts;
}
@end
Copy the code
Does not implement resolveInstanceMethod forwardingTargetForSelector methods, these methods can be cannot find a particular method can dynamically processing, should be don’t want to provide pure Swift class in this capacity.
For example, the retain release method was changed to use swift Runtime for reference count management:
- (id)retain {
auto SELF = reinterpret_cast<HeapObject *>(self);
swift_retain(SELF);
return self;
}
- (void)release {
auto SELF = reinterpret_cast<HeapObject *>(self);
swift_release(SELF);
}
Copy the code
Since pure Swift classes cannot interact directly with Objective-C, what purpose is SwiftObject designed this way?
Here are two usage scenarios:
- Is the pure
Swift
Class as aid
Parameter passing toObjective-C
Method.
- (void)test:(id)object {
[object retain];
[object performSelector:@selector(objc_instance_method)];
}
Copy the code
let object = NSObject()
test(object)
Copy the code
- Calls methods using message sending.
class SwiftClass {
@objc dynamic func objc_dynamic_instance_method(a){}}let object = SwiftClass()
object.objc_dynamic_instance_method()
Copy the code
However, the above scenario should be rarely used, and it is not clear if there is any other purpose. And by design, the pure Swift class should also be used directly by Objective-C.
Initialize an object
Objective-C
Objective-c uses Swift-NSObject subclass
class SwiftClass: NSObject {}Copy the code
SwiftClass *object = [[SwiftClass alloc] init];
Copy the code
- Because in binary
Swift
The class contains andObjective-C
Same class data information, so create way and use directlyObjective-C
The same.
Swift
Swift class
Create a pure Swift class object.
class SwiftClass {}SwiftClass(a)Copy the code
swift_getInitializedObjCClass
Class swift::swift_getInitializedObjCClass(Class c) {
[c self];// To ensure that the objC-Runtime realize class
return c;
}
Copy the code
Class objcClass = swift_getInitializedObjCClass(SwiftClass);
HeapObject *object = swift_allocObject(objcClass);
/ / release
swift_release(object);
Copy the code
nativeObjective-C
class
Create a native Objective-C class object.
@interface ObjectClass
@end
Copy the code
ObjectClass(a)Copy the code
Class objcClass = swift_getInitializedObjCClass(ObjectClass);
Metadata *metadata = swift_getObjCClassMetadata(objcClass);
ClassMetadata *classMetadata = swift_getObjCClassFromMetadata(metadata);
ObjectClass *object = [classMetadata allocWithZone] init];
/ / release
objc_release(object);
Copy the code
What does swift_getObjCClassMetadata and swift_getObjCClassFromMetadata do?
Swift – NSObject subclass
Create a swift-Nsobject subclass object.
class SwiftClass: NSObject {}SwiftClass(a)Copy the code
Class objcClass = swift_getInitializedObjCClass(SwiftClass);
HeapObject *object = objc_allocWithZone(objcClass);
/ / release
objc_release(object);
Copy the code
Swift, a generic class
Create a Swift generic class object.
class GenericClass<T> {}GenericClass<Int> ()Copy the code
MetadataResponse response = swift_getGenericMetadata();
ClassMetadata *classMetadata = swift_allocateGenericClassMetadata();
swift_initClassMetadata2(classMetadata);
HeapObject *object = swift_allocObject(objcClass);
Copy the code
- Call based on a generic type as an argument
swift_getGenericMetadata
Method to get the class object cache. There is cache directly return, no cache, callswift_allocateGenericClassMetadata
Methods.
Each different generic type creates a new ClassMetadata, which is then stored in the cache for reuse.
Swift_allocateGenericClassMetadata:
- Create a new one
ClassMetadata
Structure. - Initialize the
objc_class
andswift_class_t
Related properties, while settingisa
androData
.
Swift_initClassMetadataImpl:
- Set up the
Superclass
If no parent class is specified, it is set toSwiftObject
. - Initialize the
Vtable
. - Set up the
class_ro_t
theInstanceStart
andInstanceSize
Field, traversalivars
Modify eachivar
theoffset
. - Register the class to
objc runtime
.