Swift Runtime - 类和对象

栏目: Swift · 发布时间: 6年前

内容简介:下面是编译阶段生成的类信息:根据上面编译器生成的数据,可以得到一些信息:泛型类不会生成类元数据
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() {}
    @objc func objc_instance_method() {}
    @objc dynamic func objc_dynamic_instance_method() {}
}
复制代码

下面是编译阶段生成的类信息:

_$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
}
复制代码

根据上面编译器生成的数据,可以得到一些信息:

class

  • Swift 类编译阶段会生成与 Objective-C 一样的类元数据,这也是为什么 SwiftObjective-C 可以互相调用。

泛型类不会生成类元数据 __objc_class 结构,不过会生成 roData

  • class 如果没有显式继承某个类,都被隐式继承 SwiftObject

属性

  • 所有属性都会添加到 class_ro_t 中的 ivars 结构中,包括 private 属性。
  • 使用 @objc 修饰的属性, var 属性会添加 set/get 方法, let 属性只会添加 get 方法。

Swift 类的 属性 可以通过 objc-runtime 进行修改和获取。

方法

  • 使用 @objc 修饰的方法会添加到 ro_class_tmethods 结构中。

Swift结构

ClassMetadata

ClassMetadataSwift 中所有类元数据格式。

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;//类标示
    uint32_t instanceAddressOffset;
    uint32_t instanceSize;//对象实例大小
    uint16_t instanceAlignMask;//
    uint16_t reserved;// 保留字段
    uint32_t classSize;// 类对象的大小
    uint32_t classAddressOffset;// 
    void *description;//类描述
};
复制代码

SwiftObjective-C 的类元数据是共用的, Swift 类元数据只是 Objective-C 的基础上增加了一些字段。

源代码中也有一些地方直接使用 reinterpret_cast 进行相互转换。

Class objcClass = [objcObject class];
ClassMetadata *classAsMetadata = reinterpret_cast<const ClassMetadata *>(objcClass);
复制代码

HeapObject

Swift 中,一个 class 对象实际上就是一个 HeapObject 结构体指针。 HeapObjectHeapMetadataInlineRefCounts 组成, HeapMetadata 是类对象元数据的指针, InlineRefCounts 用于管理引用计数。

struct HeapObject {
  HeapMetadata const *metadata;
  InlineRefCounts refCounts;
};
复制代码
  • HeapMetadataObjective-C 中的 isa_t 结构一样,使用 ISA_MASK 获取到类对象。
@interface ObjcClass: NSObject {
}

ObjcClass *objcObject = [ObjcClass new];
HeapObject *heapObject = static_cast<HeapObject *>(objcObject);
ObjcClass *objcObject2 =  static_cast<ObjcClass *>(heapObject);

[heapObject retain];
复制代码

不过因为 Objective-CSwift 引用计数管理方式不一样,所以转换以后依然要使用之前的方式进行引用计数管理。

Objective-CSwift 对象结构:

Objc对象结构 {
    isa_t,
    实例变量
}
Swift对象结构 {
    metadata,
    refCounts, 
    实例变量
}
复制代码

创建对象

swift_allocObject

  • swift_allocObject 方法用于创建一个 Swift 对象。
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);//创建一个新对象,
  return object;
}
复制代码
  • 根据对象大小做字节对齐处理,之后调用 malloc 分配内存,之后会初始化实例变量。
  • metadata 表示类对象元数据。
  • requiredSizerequiredAlignmentMask 表示对象大小和字节对齐方式。

swift_initStackObject

  • 在某些场景对象创建会被编译器优化为 swift_initStackObject 方法。 swift_initStackObject 在栈上创建一个对象。没有引用计数消耗,也不用 malloc 内存。
HeapObject *
swift::swift_initStackObject(HeapMetadata const *metadata,
                             HeapObject *object) {
  object->metadata = metadata;
  object->refCounts.initForNotFreeing();
  return object;
}
复制代码

销毁对象

swift_deallocClassInstance

  • swift_deallocClassInstance 用于销毁对象,在对象 dealloc 时调用。
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);//
}
复制代码
  • 调用 objc_destructInstance 方法释放关联对象和弱引用释放处理。

Objc runtime 的对象弱引用,不是 Swift 环境的弱引用。

  • 调用 swift_deallocObject 方法调用 free 回收内存。

引用计数相关方法

  • swift_retainobjc 的实现类似,对引用计数进行 +1溢出 时将一部分引用计数值保存到 sideTable 中。
  • swift_release 对引用计数进行 -1 ,当引用计数为 0 时,调用销毁对象方法。
  • swift_weak 相关的方法用于管理 weak 弱引用。

SwiftObject

Swift 中,一个 class 如果没有显式继承其他的类,都被隐式继承 SwiftObjectSwiftObject 实现了 NSObject 协议的所有方法和一部分 NSObject 类的方法。主要是重写了一部分方法,将方法实现改为 Swift 相关方法。

@interface SwiftObject<NSObject> {
 @private
  Class isa;
  InlineRefCounts refCounts;
}
@end
复制代码

没有实现 resolveInstanceMethodforwardingTargetForSelector 等方法,这些方法可以在找不到特定方法时可以进行动态处理,应该是不想提供纯 Swift 类在这块的能力。

比如 retainrelease 方法改为了使用 swift runtime 进行引用计数管理:

- (id)retain {
  auto SELF = reinterpret_cast<HeapObject *>(self);
  swift_retain(SELF);
  return self;
}
- (void)release {
  auto SELF = reinterpret_cast<HeapObject *>(self);
  swift_release(SELF);
}
复制代码

因为纯 Swift 类不能直接与 Objective-C 交互,那么 SwiftObject 这样设计的目的是什么?

下面是两种使用场景:

  • 就是将纯 Swift 类作为 id 参数传递到 Objective-C 方法中使用。
- (void)test:(id)object {
  [object retain];
  [object performSelector:@selector(objc_instance_method)];
}
复制代码
let object = NSObject()
test(object)
复制代码
  • 使用消息发送的方式调用方法。
class SwiftClass {
    @objc dynamic func objc_dynamic_instance_method() {}
}
let object = SwiftClass()
object.objc_dynamic_instance_method()
复制代码

不过以上场景应该是很少使用的,不清楚还有没有其它目的。而且这样设计的话,纯 Swift 类也应该可以被 Objective-C 直接使用。

初始化对象

Objective-C

Objective-C使用Swift-NSObject子类

class SwiftClass: NSObject {
}
复制代码
SwiftClass *object = [[SwiftClass alloc] init];
复制代码
  • 因为二进制文件中 Swift 类包含了和 Objective-C 一样的类数据信息,所以可以直接使用 Objective-C 的方式创建。

Swift

Swift类

创建一个纯 Swift 类对象。

class SwiftClass {
}
SwiftClass()
复制代码

swift_getInitializedObjCClass

Class swift::swift_getInitializedObjCClass(Class c) {
  [c self];// 为了确保objc-runtime realize class
  return c;
}
复制代码
Class objcClass = swift_getInitializedObjCClass(SwiftClass);
HeapObject *object = swift_allocObject(objcClass);
// 释放
swift_release(object);
复制代码

原生 Objective-C

创建一个原生 Objective-C 类对象。

@interface ObjectClass
@end
复制代码
ObjectClass()
复制代码
Class objcClass = swift_getInitializedObjCClass(ObjectClass);
Metadata *metadata = swift_getObjCClassMetadata(objcClass);
ClassMetadata *classMetadata = swift_getObjCClassFromMetadata(metadata);
ObjectClass *object = [classMetadata allocWithZone] init];
// 释放
objc_release(object);
复制代码

swift_getObjCClassMetadataswift_getObjCClassFromMetadata 有什么作用?

Swift-NSObject子类

创建一个 Swift - NSObject 子类对象。

class SwiftClass: NSObject {
}
SwiftClass()
复制代码
Class objcClass = swift_getInitializedObjCClass(SwiftClass);
HeapObject *object = objc_allocWithZone(objcClass);
// 释放
objc_release(object);
复制代码

Swift泛型类

创建一个 Swift 泛型类对象。

class GenericClass<T> {
}
GenericClass<Int>()
复制代码
MetadataResponse response = swift_getGenericMetadata();
ClassMetadata *classMetadata = swift_allocateGenericClassMetadata();
swift_initClassMetadata2(classMetadata);
HeapObject *object = swift_allocObject(objcClass);
复制代码
  • 根据泛型类型作为参数,调用 swift_getGenericMetadata 方法获取类对象缓存。存在缓存直接返回,没有缓存,调用 swift_allocateGenericClassMetadata 方法。

每一个不同的泛型类型都会创建一个新的 ClassMetadata ,之后保存到缓存中复用。

swift_allocateGenericClassMetadata:

  • 创建一个新的 ClassMetadata 结构。
  • 初始化 objc_classswift_class_t 相关的属性, 同时设置 isaroData

swift_initClassMetadataImpl:

  • 设置 Superclass ,如果没有指明父类,会被设置为 SwiftObject
  • 初始化 Vtable
  • 设置 class_ro_tInstanceStartInstanceSize 字段,遍历 ivars 修改每个 ivaroffset
  • 将该类注册到 objc runtime

以上所述就是小编给大家介绍的《Swift Runtime - 类和对象》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Creative Curve

The Creative Curve

Allen Gannett / Knopf Doubleday Publishing Group / 2018-6-12

Big data entrepreneur Allen Gannett overturns the mythology around creative genius, and reveals the science and secrets behind achieving breakout commercial success in any field. We have been s......一起来看看 《The Creative Curve》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具