swiftswift 学习进阶Swift进价

swift 进阶: 类的结构

2020-12-09  本文已影响0人  欧德尔丶胡

swift 进阶之路:学习大纲

前言

一、类的初探

我们先看看类的创建流程和类的大概结构

1.0 对象的创建流程

对象初始化

  • OC: [[HJPerosn alloc] init],一般alloc申请内存空间并创建对象,init对象进行统一初始化处理。
  • Swift: HJPerosn(),直接()就完成了对象的创建。

开启汇编调试:

例子一:在swift工程中,创建一个类继承NSObject 例子二:如下不继承NSObject

最后:swift对象创建流程:
__allocating_init -> swift_allocObject -> swift_allocObject -> swift_slowAlloc ->...

在VSCode中的源码里,根据此流程逐渐对其源码进行分析如下:

1.1 swift_allocObject 源码分析
static HeapObject *_swift_allocObject_(HeapMetadata const *metadata,
                                       size_t requiredSize,
                                       size_t requiredAlignmentMask) {
  assert(isAlignmentMask(requiredAlignmentMask));
  auto object = reinterpret_cast<HeapObject *>(
      swift_slowAlloc(requiredSize, requiredAlignmentMask));//分配内存+字节对齐

 //注意:这依赖于c++ 17保证的无空指针语义
//检查我们在Windows上观察到的新分配器的位置,
// Linux和macOS。
  new (object) HeapObject(metadata);//初始化一个实例对象

  //如果启用了泄漏跟踪,请开始跟踪此对象。
  SWIFT_LEAKS_START_TRACKING_OBJECT(object);

  SWIFT_RT_TRACK_INVOCATION(object, swift_allocObject);

  return object;
}
1.2 swift_allocObject 源码分析
void *swift::swift_slowAlloc(size_t size, size_t alignMask) {
  void *p;
  //这个检查也强制“默认”对齐使用AlignedAlloc。  if (alignMask <= MALLOC_ALIGN_MASK) {
#if defined(__APPLE__)
    p = malloc_zone_malloc(DEFAULT_ZONE(), size);
#else
    p = malloc(size);// 堆中创建size大小的内存空间,用于存储实例变量
#endif
  } 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;
}
1.3 查看HeapObject 并 计算类的大小
// 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; ///引用计数

【总结】

  • Swift中实例对象,默认的比OC中多了一个refCounted引用计数大小,默认属性占16字节 : metadata(struct)8字节和refCounts(class)8字节
  • OC中实例对象的本质是结构体,是以objc_object为模板继承的,其中有一个isa指针,占8字节
1.4【验证+拓展】
//验证
class HJPerson {
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        print(class_getInstanceSize(HJPerson.self))
    }
}
打印 : 16

//拓展
class HJPerson {
    var age : Int = 20
    var name : String = "HJ"
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        print(class_getInstanceSize(HJPerson.self))
    }
}
打印 : 40

验证的确一个空类的大小为16;那么为啥第二个是40呢?
我们通过打印Int 和 String 内存大小来验证

//********* Int底层定义 *********
@frozen public struct Int : FixedWidthInteger, SignedInteger {...}

//String底层定义
@frozen public struct String {...}

//验证 
print(MemoryLayout<Int>.stride)
print(MemoryLayout<String>.stride)

打印
8
16

二、Swift中类的结构探索

2.1 metadata的底层探索
using HeapMetadata = TargetHeapMetaData<Inprocess>;
//模板类型
template <typename Runtime>
struct TargetHeapMetadata : TargetMetadata<Runtime> {
  using HeaderType = TargetHeapMetadataHeader<Runtime>;

  TargetHeapMetadata() = default;
  //初始化方法
  constexpr TargetHeapMetadata(MetadataKind kind)
    : TargetMetadata<Runtime>(kind) {}

};
// TargetMetaData 定义 
struct TargetMetaData{
   using StoredPointer = typename Runtime: StoredPointer;
    ...
    
    StoredPointer kind;
}

// Inprocess 定义
struct Inprocess{
    ...
    using StoredPointer = uintptr_t;
    ...
}

//******** uintptr_t 定义 ********
typedef unsigned long uintptr_t;
2.2 getClassObject
 const TargetClassMetadata<Runtime> *getClassObject() const;
//******** 具体实现 ********
template<> inline const ClassMetadata *
 Metadata::getClassObject() const {
   //匹配kind
   switch (getKind()) {
     //如果kind是class
   case MetadataKind::Class: {
     // Native Swift class metadata is also the class object.
     //将当前指针强转为ClassMetadata类型
     return static_cast<const ClassMetadata *>(this);
   }
   case MetadataKind::ObjCClassWrapper: {
     // Objective-C class objects are referenced by their Swift metadata wrapper.
     auto wrapper = static_cast<const ObjCClassWrapperMetadata *>(this);
     return wrapper->Class;
   }
   // Other kinds of types don't have class objects.
   default:
     return nullptr;
   }
 }

通过lldb来验证

  • po metadata->getKind(),得到其kind是Class
  • po metadata->getClassObject()、x/8g 0x0000000110efdc70,这个地址中存储的是元数据信息!

所以TargetMetadataTargetClassMetadata本质上是一样的,因为在内存结构中,可以直接进行指针的转换,所以可以说,我们认为的结构体,其实就是TargetClassMetadata

2.3 TargetClassMetadata

进入TargetClassMetadata定义,继承自TargetAnyClassMetadata,有以下这些属性,这也是类结构的部分

template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
    ...
    //swift特有的标志
    ClassFlags Flags;
    //实力对象内存大小
    uint32_t InstanceSize;
    //实例对象内存对齐方式
    uint16_t InstanceAlignMask;
    //运行时保留字段
    uint16_t Reserved;
    //类的内存大小
    uint32_t ClassSize;
    //类的内存首地址
    uint32_t ClassAddressPoint;
  ...
}
struct swift_class_t: NSObject{
    void *kind;//相当于OC中的isa,kind的实际类型是unsigned long
    void *superClass;
    void *cacheData;
    void *data;
    uint32_t flags; //4字节
    uint32_t instanceAddressOffset;//4字节
    uint32_t instanceSize;//4字节
    uint16_t instanceAlignMask;//2字节
    uint16_t reserved;//2字节
    
    uint32_t classSize;//4字节
    uint32_t classAddressOffset;//4字节
    void *description;
    ...
}

三、分析思路整理

四、swif与OC 类的结构对比

上一篇 下一篇

猜你喜欢

热点阅读