美文网首页
Swift 中的类

Swift 中的类

作者: kwdx | 来源:发表于2020-05-17 18:26 被阅读0次

    Swift 中,类对象的结构是否和 Objective-C 一样呢?

    SwiftObject

    在swift中,如果没有明确声明父类的类,则会隐式地继承自 SwiftObject (支持与 Objective-C 混编的前提下,因为 SwiftObject 是一个 Objective-C 类),隐式继承来源于 swiftABI/TypeLayout.rst 文档。

    关于 SwiftObject 的定义如下:

    #if SWIFT_OBJC_INTEROP
    #if __OBJC__
    
    // Source code: "SwiftObject"
    // Real class name: mangled "Swift._SwiftObject"
    #define SwiftObject _TtCs12_SwiftObject
    
    #if __has_attribute(objc_root_class)
    __attribute__((__objc_root_class__))
    #endif
    SWIFT_RUNTIME_EXPORT @interface SwiftObject<NSObject> {
     @private
      Class isa;
      SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    }
    
    ...
      
    @end
    
    namespace swift {
    
    id getDescription(OpaqueValue *value, const Metadata *type);
    
    }
    
    #endif
    #endif
    
    namespace swift {
    
    /// Get the NSObject metadata.
    const Metadata *getNSObjectMetadata();
    
    }
    
    #endif
    

    SwiftObject 的声明是 SWIFT_OBJC_INTEROPtrue 的情况下才有声明的,而在苹果平台下,都是支持 swiftObjective-C 进行混编的,因此 SWIFT_OBJC_INTEROP1(true)SWIFT_OBJC_INTEROP 宏的定义可在 Config.h 中找到

    /// Does the current Swift platform support "unbridged" interoperation
    /// with Objective-C?  If so, the implementations of various types must
    /// implicitly handle Objective-C pointers.
    ///
    /// Apple platforms support this by default.
    #ifndef SWIFT_OBJC_INTEROP
    #ifdef __APPLE__
    #define SWIFT_OBJC_INTEROP 1
    #else
    #define SWIFT_OBJC_INTEROP 0
    #endif
    #endif
    

    SwiftObject 的定义中可以看到

    • 第一个成员变量和 Objective-C 一样是 isa 指针,暂时猜想和 Objective-C 中的 isa 指针功能一样
    • 第二个成员变量是一个 SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS 宏,其定义可在 HeapObject.hRefCount.h 中找到,从命名上看是引用计数器
    // RefCount.h
    // This definition is a placeholder for importing into Swift.
    // It provides size and alignment but cannot be manipulated safely there.
    typedef struct {
      __swift_uintptr_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE;
    } InlineRefCountsPlaceholder;
    
    #if defined(__swift__)
    
    typedef InlineRefCountsPlaceholder InlineRefCounts;
    
    #else
    
    // HeapObject.h
    namespace swift {
    
    struct InProcess;
    
    template <typename Target> struct TargetHeapMetadata;
    using HeapMetadata = TargetHeapMetadata<InProcess>;
    #else
    typedef struct HeapMetadata HeapMetadata;
    typedef struct HeapObject HeapObject;
    #endif
    
    // The members of the HeapObject header that are not shared by a
    // standard Objective-C instance
    #define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
      InlineRefCounts refCounts
    
    /// The Swift heap-object header.
    /// This must match RefCountedStructTy in IRGen.
    struct HeapObject {
      /// This is always a valid pointer to a metadata object.
      HeapMetadata const *metadata;
    
      SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    
    #ifndef __swift__
      HeapObject() = default;
    
      // Initialize a HeapObject header as appropriate for a newly-allocated object.
      constexpr HeapObject(HeapMetadata const *newMetadata) 
        : metadata(newMetadata)
        , refCounts(InlineRefCounts::Initialized)
      { }
      
      // Initialize a HeapObject header for an immortal object
      constexpr HeapObject(HeapMetadata const *newMetadata,
                           InlineRefCounts::Immortal_t immortal)
      : metadata(newMetadata)
      , refCounts(InlineRefCounts::Immortal)
      { }
    
    #ifndef NDEBUG
      void dump() const LLVM_ATTRIBUTE_USED;
    #endif
    
    #endif // __swift__
    };
    

    在下文的所有测试代码中,均使用自定义 Person

    class Person {
        var name: String
        var age: Int
        
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
        
        func printData() {
            print("name=\(name), age=\(age)")
        }
    }
    

    验证父类

    下面通过2种方式来验证在 swift 中,没有明确声明父类的类,会隐式继承 SwiftObject

    • Objective-C runtime
    print(class_getSuperclass(Person.self))
    

    打印结果为:

    Optional(_TtCs12_SwiftObject)
    
    • MachO文件
    Person Superclass

    _$s11ClassStruct6PersonCN 这个结构体可以理解为 Person 类的类对象,其 superclass 指针指向 _TtCs12_SwiftObject

    _TtCs12_SwiftObjectSwiftObject 的真实类名,可在 SwiftObject.h 的文档中找到相关的描述:

    // Source code: "SwiftObject"
    // Real class name: mangled "Swift._SwiftObject"
    #define SwiftObject _TtCs12_SwiftObject
    

    HeapObject

    swift 中,基本上分配在堆上的对象都是一个 HeapObject。其定义可在 HeapObject.h 中找到:

    // The members of the HeapObject header that are not shared by a
    // standard Objective-C instance
    #define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
      InlineRefCounts refCounts
    
    /// The Swift heap-object header.
    /// This must match RefCountedStructTy in IRGen.
    struct HeapObject {
      /// This is always a valid pointer to a metadata object.
      HeapMetadata const *metadata;
    
      SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    
      ...
    };
    

    metadata 是指向类结构 HeapMetadata 的指针,refCounts 所包含的信息比较多,使用了掩码,其中包含了引用计数。

    因此 Person 的实例对象的成员变量是在偏移量为16个字节开始,前16个字节分别存放 metadata 的指针和 refCounts 的引用计数,Person 的实例对象对应的内存结构可以对应如下的结构体:

    struct PersonStruct {
        // 指向类对象的指针
        let metaData: UnsafePointer
        let refCounts: __uint64_t
        var name: String
        let age: Int
    }
    

    定义一个简单的 person 实例对象,并定义一个结构体 personStruct 指向 person 内存,并修改 personStruct 结构体的 name 属性和 age 属性,看 person 对象的属性是否有对应的修改

    var person = Person(name: "swift", age: 6)
    // 将指向person对象内存地址的指针转成指向PersonStruct结构体的指针,实则还是指向同一个内存地址
    var pStructPointer = Unmanaged.passUnretained(person).toOpaque().bindMemory(to: PersonStruct.self, capacity: personSize)
    print(pStructPointer)
    
    pStructPointer.pointee.name = "struct"
    pStructPointer.pointee.age = 1
    person.printData()
    // 打印结果为:name=struct, age=1
    

    这里需要注意的是,不能把指向 person 实例对象内存地址的指针转成 PersonStruct 结构体,再修改结构体的属性值。

    var pStruct = Unmanaged.passUnretained(person).toOpaque().bindMemory(to: PersonStruct.self, capacity: personSize).pointee
    

    这种写法是不会改变 person 对象的属性,因为结构体是值类型,相当于把 person 内存的值都拷贝了一份

    HeapMetadata

    HeapMetadata 可理解为 Objective-C 中的类对象和元类对象,其对应的结构可在 Metadata.h 中找到

    /// In-process native runtime target.
    ///
    /// For interactions in the runtime, this should be the equivalent of working
    /// with a plain old pointer type.
    struct InProcess {
      static constexpr size_t PointerSize = sizeof(uintptr_t);
      using StoredPointer = uintptr_t;
      using StoredSignedPointer = uintptr_t;
      using StoredSize = size_t;
      using StoredPointerDifference = ptrdiff_t;
    
      static_assert(sizeof(StoredSize) == sizeof(StoredPointerDifference),
                    "target uses differently-sized size_t and ptrdiff_t");
      
      template <typename T>
      using Pointer = T*;
    
      template <typename T>
      using SignedPointer = T;
      
      ...
    };
    
    /// The common structure of all type metadata.
    template <typename Runtime>
    struct TargetMetadata {
      using StoredPointer = typename Runtime::StoredPointer;
    
      /// The basic header type.
      typedef TargetTypeMetadataHeader<Runtime> HeaderType;
    
      ...
        
    private:
      /// The kind. Only valid for non-class metadata; getKind() must be used to get
      /// the kind value.
      StoredPointer Kind;
    public:
      /// Get the metadata kind.
      MetadataKind getKind() const {
        return getEnumeratedMetadataKind(Kind);
      }
      
      /// Set the metadata kind.
      void setKind(MetadataKind kind) {
        Kind = static_cast<StoredPointer>(kind);
      }
    
    #if SWIFT_OBJC_INTEROP
    protected:
      const TargetAnyClassMetadata<Runtime> *getClassISA() const {
        return reinterpret_cast<const TargetAnyClassMetadata<Runtime> *>(Kind);
      }
      void setClassISA(const TargetAnyClassMetadata<Runtime> *isa) {
        Kind = reinterpret_cast<StoredPointer>(isa);
      }
    #endif
    
    public:
      /// Is this a class object--the metadata record for a Swift class (which also
      /// serves as the class object), or the class object for an ObjC class (which
      /// is not metadata)?
      bool isClassObject() const {
        return static_cast<MetadataKind>(getKind()) == MetadataKind::Class;
      }
      
      ...
    };
    
    /// The common structure of all metadata for heap-allocated types.  A
    /// pointer to one of these can be retrieved by loading the 'isa'
    /// field of any heap object, whether it was managed by Swift or by
    /// Objective-C.  However, when loading from an Objective-C object,
    /// this metadata may not have the heap-metadata header, and it may
    /// not be the Swift type metadata for the object's dynamic type.
    template <typename Runtime>
    struct TargetHeapMetadata : TargetMetadata<Runtime> {
      using HeaderType = TargetHeapMetadataHeader<Runtime>;
    
      TargetHeapMetadata() = default;
      constexpr TargetHeapMetadata(MetadataKind kind)
        : TargetMetadata<Runtime>(kind) {}
    #if SWIFT_OBJC_INTEROP
      constexpr TargetHeapMetadata(TargetAnyClassMetadata<Runtime> *isa)
        : TargetMetadata<Runtime>(isa) {}
    #endif
    };
    using HeapMetadata = TargetHeapMetadata<InProcess>;
    

    上面看起来可能还是有点乱,可以看看下面只保留成员变量的结构体

    struct TargetMetadata {
      uintptr_t Kind;
    }
    
    struct TargetHeapMetadata : TargetMetadata<Runtime> {
      
    };
    

    这么一看,结构体中只有一个成员变量 Kind,其实 Kind 属性为 MetadataKind 类型,记录着此 metadata 的实际类型,其定义在 MetadataValues.h & MetadataKind.def 中能找到:

    /// Non-type metadata kinds have this bit set.
    const unsigned MetadataKindIsNonType = 0x400;
    
    /// Non-heap metadata kinds have this bit set.
    const unsigned MetadataKindIsNonHeap = 0x200;
    
    // The above two flags are negative because the "class" kind has to be zero,
    // and class metadata is both type and heap metadata.
    
    /// Runtime-private metadata has this bit set. The compiler must not statically
    /// generate metadata objects with these kinds, and external tools should not
    /// rely on the stability of these values or the precise binary layout of
    /// their associated data structures.
    const unsigned MetadataKindIsRuntimePrivate = 0x100;
    
    /// Kinds of Swift metadata records.  Some of these are types, some
    /// aren't.
    enum class MetadataKind : uint32_t {
    #define METADATAKIND(name, value) name = value,
    #define ABSTRACTMETADATAKIND(name, start, end)                                 \
      name##_Start = start, name##_End = end,
    #include "MetadataKind.def"
      /// ABSTRACTMETADATAKIND(Name, Start, End)
    ///   Represents an abstraction categorization of a range of metadata kind
    ///   values. Name is the identifier of the range and Start, End are the
    ///   beginning and end of the range.
    #ifndef ABSTRACTMETADATAKIND
    #define ABSTRACTMETADATAKIND(Name, Start, End)
    #endif
    
    /// NOMINALTYPEMETADATAKIND(Name, Value)
    ///   Represents the native metadata kind for a swift nominal type. Name is the
    ///   name of the kind and Value is the integral value used to identify the
    ///   value. Delegates to METADATAKIND if not defined.
    #ifndef NOMINALTYPEMETADATAKIND
    #define NOMINALTYPEMETADATAKIND(Name, Value) METADATAKIND(Name, Value)
    #endif
    
    /// A class type.
    NOMINALTYPEMETADATAKIND(Class, 0)
    
    /// A struct type.
    NOMINALTYPEMETADATAKIND(Struct, 0 | MetadataKindIsNonHeap)
    
    /// An enum type.
    /// If we add reference enums, that needs to go here.
    NOMINALTYPEMETADATAKIND(Enum, 1 | MetadataKindIsNonHeap)
    
    /// An optional type.
    NOMINALTYPEMETADATAKIND(Optional, 2 | MetadataKindIsNonHeap)
    
    /// A foreign class, such as a Core Foundation class.
    METADATAKIND(ForeignClass, 3 | MetadataKindIsNonHeap)
    
    /// A type whose value is not exposed in the metadata system.
    METADATAKIND(Opaque, 0 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// A tuple.
    METADATAKIND(Tuple, 1 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// A monomorphic function.
    METADATAKIND(Function, 2 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// An existential type.
    METADATAKIND(Existential, 3 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// A metatype.
    METADATAKIND(Metatype, 4 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// An ObjC class wrapper.
    METADATAKIND(ObjCClassWrapper, 5 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// An existential metatype.
    METADATAKIND(ExistentialMetatype, 6 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
    
    /// A heap-allocated local variable using statically-generated metadata.
    METADATAKIND(HeapLocalVariable, 0 | MetadataKindIsNonType)
    
    /// A heap-allocated local variable using runtime-instantiated metadata.
    METADATAKIND(HeapGenericLocalVariable,
                 0 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
    
    /// A native error object.
    METADATAKIND(ErrorObject,
                 1 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
      
      LastEnumerated = 0x7FF,
    };
    

    可能不太好看,MetadataKind 是枚举类型,其值如下表格:

    name Value
    Class 0x0
    Struct 0x200
    Enum 0x201
    Optional 0x202
    ForeignClass 0x203
    Opaque 0x300
    Tuple 0x301
    Function 0x302
    Existential 0x303
    Metatype 0x304
    ObjCClassWrapper 0x305
    ExistentialMetatype 0x306
    HeapLocalVariable 0x400
    HeapGenericLocalVariable 0x500
    ErrorObject 0x501
    LastEnumerated 0x7FF

    TargetMetadata 结构体中有个函数可以获取其类型

    struct TargetMetadata {
      ...
        
    private:
      /// The kind. Only valid for non-class metadata; getKind() must be used to get
      /// the kind value.
      StoredPointer Kind;
    public:
      /// Get the metadata kind.
      MetadataKind getKind() const {
        return getEnumeratedMetadataKind(Kind);
      }
      
      /// Set the metadata kind.
      void setKind(MetadataKind kind) {
        Kind = static_cast<StoredPointer>(kind);
      }
      ...
    }
    
    /// Try to translate the 'isa' value of a type/heap metadata into a value
    /// of the MetadataKind enum.
    inline MetadataKind getEnumeratedMetadataKind(uint64_t kind) {
      if (kind > LastEnumeratedMetadataKind)
        return MetadataKind::Class;
      return MetadataKind(kind);
    }
    

    如果 kind 大于 0x7FF 的话,都为 MetadataKind::Class 类型。下面可以看看 Person 类的 Kind

    print(String(format: "0x%02lx", Unmanaged.passUnretained(person).toOpaque().load(as: __uint64_t.self)))
    // 打印结果:0x1000092d8
    

    也可以通过 LLDB 来获取其值:

    Person Kind

    因此 getEnumeratedMetadataKind(uint64_t kind) 返回 MetadataKind::Class

    /// Get the nominal type descriptor if this metadata describes a nominal type,
    /// or return null if it does not.
    ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
    getTypeContextDescriptor() const {
        switch (getKind()) {
      case MetadataKind::Class: {
          const auto cls = static_cast<const TargetClassMetadata<Runtime> *>(this);
        if (!cls->isTypeMetadata())
            return nullptr;
        if (cls->isArtificialSubclass())
            return nullptr;
        return cls->getDescription();
        }
        case MetadataKind::Struct:
        case MetadataKind::Enum:
        case MetadataKind::Optional:
        return static_cast<const TargetValueMetadata<Runtime> *>(this)
              ->Description;
        case MetadataKind::ForeignClass:
        return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
              ->Description;
        default:
        return nullptr;
        }
    }
    

    在函数 getTypeContextDescriptor() 中可以看到,如果 Kind 类型为 MetadataKind::Class 的话,可以转成 TargetClassMetadata 结构体

    /// The structure of all class metadata.  This structure is embedded
    /// directly within the class's heap metadata structure and therefore
    /// cannot be extended without an ABI break.
    ///
    /// Note that the layout of this type is compatible with the layout of
    /// an Objective-C class.
    template <typename Runtime>
    struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
      using StoredPointer = typename Runtime::StoredPointer;
      using StoredSize = typename Runtime::StoredSize;
    
      // The remaining fields are valid only when isTypeMetadata().
      // The Objective-C runtime knows the offsets to some of these fields.
      // Be careful when accessing them.
    
      /// Swift-specific class flags.
      ClassFlags Flags;
    
      /// The address point of instances of this type.
      uint32_t InstanceAddressPoint;
    
      /// The required size of instances of this type.
      /// 'InstanceAddressPoint' bytes go before the address point;
      /// 'InstanceSize - InstanceAddressPoint' bytes go after it.
      uint32_t InstanceSize;
    
      /// The alignment mask of the address point of instances of this type.
      uint16_t InstanceAlignMask;
    
      /// Reserved for runtime use.
      uint16_t Reserved;
    
      /// The total size of the class object, including prefix and suffix
      /// extents.
      uint32_t ClassSize;
    
      /// The offset of the address point within the class object.
      uint32_t ClassAddressPoint;
    
      // Description is by far the most likely field for a client to try
      // to access directly, so we force access to go through accessors.
    private:
      /// An out-of-line Swift-specific description of the type, or null
      /// if this is an artificial subclass.  We currently provide no
      /// supported mechanism for making a non-artificial subclass
      /// dynamically.
      TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
    
    public:
      /// A function for destroying instance variables, used to clean up after an
      /// early return from a constructor. If null, no clean up will be performed
      /// and all ivars must be trivial.
      TargetSignedPointer<Runtime, ClassIVarDestroyer * __ptrauth_swift_heap_object_destructor> IVarDestroyer;
      
      ...
    };
    using ClassMetadata = TargetClassMetadata<InProcess>;
    
    /// The portion of a class metadata object that is compatible with
    /// all classes, even non-Swift ones.
    template <typename Runtime>
    struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
      using StoredPointer = typename Runtime::StoredPointer;
      using StoredSize = typename Runtime::StoredSize;
    
    #if SWIFT_OBJC_INTEROP
      // Allow setting the metadata kind to a class ISA on class metadata.
      using TargetMetadata<Runtime>::getClassISA;
      using TargetMetadata<Runtime>::setClassISA;
    #endif
    
      // Note that ObjC classes does not have a metadata header.
    
      /// The metadata for the superclass.  This is null for the root class.
      ConstTargetMetadataPointer<Runtime, swift::TargetClassMetadata> Superclass;
    
      // TODO: remove the CacheData and Data fields in non-ObjC-interop builds.
    
      /// The cache data is used for certain dynamic lookups; it is owned
      /// by the runtime and generally needs to interoperate with
      /// Objective-C's use.
      TargetPointer<Runtime, void> CacheData[2];
    
      /// The data pointer is used for out-of-line metadata and is
      /// generally opaque, except that the compiler sets the low bit in
      /// order to indicate that this is a Swift metatype and therefore
      /// that the type metadata header is present.
      StoredSize Data;
    };
    using AnyClassMetadata =
      TargetAnyClassMetadata<InProcess>;
    

    接下来通过验证一下,可以定义如下 C++ 结构体:

    struct TargetAnyClassMetadata {
        struct TargetAnyClassMetadata* Kind;
        void* superClass;
        void* CacheData[2];
        void* Data;
    };
    
    struct TargetClassMetadata {
        uintptr_t Kind;  
        struct AnyClassHeapMetadata* superClass;
        void* CacheData[2];
        void* Data;
      
        uint32_t Flags;
        uint32_t InstanceAddressPoint;
        uint32_t InstanceSize;
        uint16_t InstanceAlignMask;
        uint16_t Reserved;
        uint32_t ClassSize;
        uint32_t ClassAddressPoint;
        uintptr_t Description;
        uintptr_t IVarDestroyer;
    };
    

    打印 TargetClassMetadata 中的 InstanceSize 的值,即为 Person 类创建的实例对象所占的内存大小

    let personMetaData = pStructPointer.pointee.metaData.bindMemory(to: TargetClassMetadata.self, capacity: MemoryLayout<TargetClassMetadata>.stride).pointee
    print(personMetaData.InstanceSize)
    // 打印结果为:40
    

    Person 中,name 属性占用16字节,age 属性占用8字节,隐式继承的 SwiftObject 的成员变量 metadata 指针和 refCounts 分别都占用 8字节,加起来总共占用40个字节用于存放成员变量,但由于内存对齐,实际分配的内存为48字节

    print("person对象占用的内存大小: \(malloc_size(pPointer))")
    // 打印结果为:person对象占用的内存大小: 48
    

    我们可以继续获取其 Kind 值所指向的“元类对象”,可理解为 Objective-C 中的元类对象。下面可以打印 Person 的类对象和元类对象的地址:

    /// 类对象地址指针
    let clsAddress = pStructPointer.pointee.metaData
    /// Person元类对象地址
    let metaAddress = String(format: "0x%02lx", personMetaData.Kind)
    print("Person类对象地址: \(clsAddress)")
    print("Person元类对象地址: \(metaAddress)")
    

    打印结果为:

    Person类对象地址: 0x10000a2d8
    Person元类对象地址: 0x10000a2a0
    

    使用 Hopper Disassembler 查看MachO 文件

    MachO

    ⚠️:不能通过 Objective-C 的运行时来获取 Swift 类的类对象和元类对象,通过 objc_getClass()objc_getMetaClass() 这些 Objective-C 运行时runtime 方法获取到的类对象和元类对象是动态创建出来的,不可取

    RefCount 引用计数

    实例对象的第二个成员变量 refCounts 从名字上看是存放引用计数,但并不是直接存放的,而且采用了掩码进行存放,类似于 Objective-C 中的 isa 指针,其定义可在 RefCount.h 中找到

    // 64-bit inline
    // 64-bit out of line
    // 32-bit out of line
    template <>
    struct RefCountBitOffsets<8> {
      /*
       The bottom 32 bits (on 64 bit architectures, fewer on 32 bit) of the refcount
       field are effectively a union of two different configurations:
       
       ---Normal case---
       Bit 0: Does this object need to call out to the ObjC runtime for deallocation
       Bits 1-31: Unowned refcount
       
       ---Immortal case---
       All bits set, the object does not deallocate or have a refcount
       */
      static const size_t PureSwiftDeallocShift = 0;
      static const size_t PureSwiftDeallocBitCount = 1;
      static const uint64_t PureSwiftDeallocMask = maskForField(PureSwiftDealloc);
    
      static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc);
      static const size_t UnownedRefCountBitCount = 31;
      static const uint64_t UnownedRefCountMask = maskForField(UnownedRefCount);
    
      static const size_t IsImmortalShift = 0; // overlaps PureSwiftDealloc and UnownedRefCount
      static const size_t IsImmortalBitCount = 32;
      static const uint64_t IsImmortalMask = maskForField(IsImmortal);
    
      static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
      static const size_t IsDeinitingBitCount = 1;
      static const uint64_t IsDeinitingMask = maskForField(IsDeiniting);
    
      static const size_t StrongExtraRefCountShift = shiftAfterField(IsDeiniting);
      static const size_t StrongExtraRefCountBitCount = 30;
      static const uint64_t StrongExtraRefCountMask = maskForField(StrongExtraRefCount);
      
      static const size_t UseSlowRCShift = shiftAfterField(StrongExtraRefCount);
      static const size_t UseSlowRCBitCount = 1;
      static const uint64_t UseSlowRCMask = maskForField(UseSlowRC);
    
      static const size_t SideTableShift = 0;
      static const size_t SideTableBitCount = 62;
      static const uint64_t SideTableMask = maskForField(SideTable);
      static const size_t SideTableUnusedLowBits = 3;
    
      static const size_t SideTableMarkShift = SideTableBitCount;
      static const size_t SideTableMarkBitCount = 1;
      static const uint64_t SideTableMarkMask = maskForField(SideTableMark);
    };
    
    typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;
    
    template <typename RefCountBits>
    class RefCounts {
      std::atomic<RefCountBits> refCounts;
    
        ...
    };
    
    typedef RefCounts<InlineRefCountBits> InlineRefCounts;
    typedef RefCounts<SideTableRefCountBits> SideTableRefCounts;
    

    掩码对应的值如下表所示:

    掩码名称 掩码起始位置 位数
    PureSwiftDeallocShift 0x1UL<<0 1
    UnownedRefCountShift 0x1UL<<1 31
    IsImmortalShift 0x1UL<<0 32
    IsDeinitingShift 0x1UL<<32 1
    StrongExtraRefCountShift 0x1UL<<33 30
    UseSlowRCShift 0x1UL<<63 1
    SideTableShift 0x1UL<<0 62
    SideTableMarkShift 0x1UL<<62 1
    RefCountBits

    通过代码验证一下 UnownedRefCountShiftStrongExtraRefCountShift

    let p1 = Person(name: "swift", age: 6)
    let p2 = p1
    let p3 = p1
    unowned let p4 = p1
    unowned let p5 = p1
    

    上面有3个强引用,2个无主引用(总数为2+1,初始值为1),接下来获取 p1 对象的 refCounts 值:

    person RefCounts

    0x0000000600000006 中对应强引用计数 StrongExtraRefCountShift 的值为 0x3,对应无主引用计数 UnownedRefCountShift 的值为0x3

    若对象存在弱引用,其弱引用计数在 sidetable 中的

    weak var p6 = p1
    
    Weak RefCounts

    其值已发生改变,SideTableMarkShift 标志位为 1。

    Person 内存图解

    我自己画了一幅图来描述 Person 的内存结构:

    Memory Layout

    ⚠️:Person 元类对象不是TargetClassMetadata类型的,Person 类对象才是

    相关文章

      网友评论

          本文标题:Swift 中的类

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