美文网首页swift知识技巧搜集
Swift Runtime - 类和对象

Swift Runtime - 类和对象

作者: hexiaoxiao | 来源:发表于2019-06-24 15:50 被阅读0次

    编译阶段

    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 - 类和对象

        本文链接:https://www.haomeiwen.com/subject/hweugqtx.html