iOS开发技术

OC对象的结构

2020-09-14  本文已影响0人  浪的出名

Objective-C的本质

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
如果需要链接其他框架,使用-framework参数。比如-framework UIKit

Objective-C对象在内存中的布局

struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _age;
    int _height;
};
struct NSObject_IMPL {
    Class isa;
};
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    ......
}
/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
struct objc_class {
    Class isa;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    ......
}
//此处只列出核心的代码
struct class_data_bits_t {
    ......
    class_rw_t* data() {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    ......
}
struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint16_t witness;
    explicit_atomic<uintptr_t> ro_or_rw_ext;
    Class firstSubclass;
    Class nextSiblingClass;
 private:
    using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t *, class_rw_ext_t *>;   
    ...
public:
const class_ro_t *ro() const { //获取class_ro_t类信息
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>()->ro;
        }
        return v.get<const class_ro_t *>();
    }
const method_array_t methods() const { //方法列表
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
        }
    }
const property_array_t properties() const { //属性列表
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>()->baseProperties};
        }
    }
const protocol_array_t protocols() const { //协议列表
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
        }
    }    
    ...
    const class_ro_t *ro;
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    char *demangledName;
    uint32_t version;
};

继续查看class_ro_t的结构如下:

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;  //当前instance对象占用内存的大小
    const uint8_t * ivarLayout;
    const char * name;              //类名
    method_list_t * baseMethodList; //基础的方法列表
    protocol_list_t * baseProtocols;//基础协议列表
    const ivar_list_t * ivars;      //成员变量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;//基本属性列表
}

此处就不得不说class_rw_t和class_ro_t的区别了,class_ro_t中存放着类最原始的方法列表,属性列表等等,这些在编译期就已经生成了,而且它是只读的,在运行期无法修改。而class_rw_t不仅包含了编译器生成的方法列表、属性列表,还包含了运行时动态生成的方法和属性。它是可读可写的。

通过lldb打印出oc对象的结构

通过类信息直接打印

 p (objc_class *)$0
(objc_class *) $5 = 0x00000001000025b0
(lldb) p *$5
(objc_class) $6 = {
  objc_object = {
    isa = {
      cls = 0x0000000100002588
      bits = 4294976904
       = {
        nonpointer = 0
        has_assoc = 0
        has_cxx_dtor = 0
        shiftcls = 536872113
        magic = 0
        weakly_referenced = 0
        deallocating = 0
        has_sidetable_rc = 0
        extra_rc = 0
      }
    }
  }
  superclass = NSObject
  cache = {
    _buckets = {
      std::__1::atomic<bucket_t *> = 0x00000001003ea460 {
        _sel = {
          std::__1::atomic<objc_selector *> = 0x0000000000000000
        }
        _imp = {
          std::__1::atomic<unsigned long> = 0
        }
      }
    }
    _mask = {
      std::__1::atomic<unsigned int> = 0
    }
    _flags = 32804
    _occupied = 0
  }
  bits = (bits = 4320180788)
}
(lldb) p $6.bits
(class_data_bits_t) $7 = (bits = 4320180788)
(lldb) p $6.data()
(class_rw_t *) $8 = 0x000000010180ba30
(lldb) p *$8
(class_rw_t) $9 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294976120
  }
  firstSubclass = nil
  nextSiblingClass = NSUUID
}
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED//电脑或模拟器
    explicit_atomic<struct bucket_t *> _buckets;//explicit_atomic相当于做了一个线程保护,实际类型为一个结构体指针占8个字节
    explicit_atomic<mask_t> _mask;//typedef uint32_t mask_t; 占4个字节
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16//(__arm64__) && __LP64__真机设备
    explicit_atomic<uintptr_t> _maskAndBuckets;// typedef unsigned long           uintptr_t; 8个字节
    mask_t _mask_unused;//和上面一样4个字节
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4//(__arm64__) && !__LP64__低于64位的真机设备
    // _maskAndBuckets stores the mask shift in the low 4 bits, and
    // the buckets pointer in the remainder of the value. The mask
    // shift is the value where (0xffff >> shift) produces the correct
    // mask. This is equal to 16 - log2(cache_size).
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;
#else
#error Unknown cache mask storage type.
#endif
    
#if __LP64__
    uint16_t _flags;   //typedef unsigned short uint16_t; 2个字节
#endif
    uint16_t _occupied; //2个字节
};
//所以无论在什么设备上cache_t都是16个字节
(lldb) p/x Person.class
(Class) $0 = 0x00000001000025b0 Person
(lldb) p/x (class_data_bits_t *)(0x00000001000025b0 + 0x20)
(class_data_bits_t *) $1 = 0x00000001000025d0
(lldb) p *$1
(class_data_bits_t) $2 = (bits = 4320180788)
(lldb) p/x $2.data()
(class_rw_t *) $3 = 0x000000010180ba30
(lldb) p *$3
(class_rw_t) $4 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294976120
  }
  firstSubclass = nil
  nextSiblingClass = NSUUID
}

通过定义结构体的方法查看对象的结构

struct xq_bucket_t {
//#if __arm64__
//    explicit_atomic<uintptr_t> _imp;
//    explicit_atomic<SEL> _sel;
//#else
    IMP _imp;
    SEL _sel;
//#endif
};
struct xq_cache_t {
//#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
//    struct xq_bucket_t * _buckets;
//    mask_t _mask;
//#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    uintptr_t _maskAndBuckets;
    mask_t _mask_unused;
//#endif
//#if __LP64__
    uint16_t _flags;
//#endif
    uint16_t _occupied;

};
struct xq_class_data_bits_t {
    // Values are the FAST_ flags above.
    uintptr_t bits;

};
struct xq_objc_class {
    Class ISA;
    Class superclass;
    struct xq_cache_t cache;             // formerly cache pointer and vtable
    struct xq_class_data_bits_t bits;
};

Person *p = [Person alloc];
struct xq_objc_class *pClass = (__bridge struct xq_objc_class *)([Person class]);
// 通过强转也可以达到调试效果
上一篇 下一篇

猜你喜欢

热点阅读