[iOS]2、類的原理

1、class的底層結(jié)構(gòu)探究

通過如下代碼進(jìn)行 class 的結(jié)構(gòu)調(diào)試

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [[Person alloc] init];
        NSLog(@"Person");
    }
    return 0;
}
// Person.h
@interface Person : NSObject {
    NSString *subject;
}
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *hobby;
- (void)sayNB;
+ (void)say666;
@end
// Person.m
@implementation Person
- (void)sayNB {}
+ (void)say666 {}
@end

補(bǔ)充:
1、objc_class 繼承自 objc_object
2、pobjc_class 對(duì)象,Person 對(duì)象為 objc_object結(jié)構(gòu)體
3、idobjc_object* 指針
4、classobjc_object的指針地址

1.1、objc_class 繼承自 objc_object
struct objc_object {
private:
    isa_t isa;
}

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;
}

從類的結(jié)構(gòu)中分析得知,前 8 個(gè)字節(jié)為 isa, 后 8 個(gè)字節(jié)為 superclass
控制臺(tái)操作:
x/4gx Person.class Person 元類的內(nèi)存結(jié)構(gòu)

0x100008380: 0x00000001000083a8 0x000000010036e140
0x100008390: 0x000000010066c070 0x0002802800000003

po 0x00000001000083a8 第一個(gè) 8 個(gè)字節(jié)(isa)打印結(jié)果

Person

po 0x000000010036e140 第二個(gè) 8個(gè)字節(jié)(superclass)打印結(jié)果

NSObject
1.2、cache_t

cache_t 的結(jié)構(gòu)體如下

struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask; // 8
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;  // 4
#if __LP64__
            uint16_t                   _flags; // 2
#endif
            uint16_t                   _occupied; // 2
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache; // 8
    };
}
struct explicit_atomic : public std::atomic<T> {
}

explicit_atomic 為泛型結(jié)構(gòu),大小為泛型的類型
cache_t 結(jié)構(gòu)體的大小為 16 個(gè)字節(jié)

1.3、class_data_bits_t
struct class_data_bits_t {
    friend objc_class;
    // Values are the FAST_ flags above.
    uintptr_t bits;
public:
    class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
}

綜上 class_data_bits_t 位于 objc_class 的第 36 個(gè)字節(jié)處
p/x 0x100008380+0x20

(long) $7 = 0x00000001000083a0

p (class_data_bits_t *)0x00000001000083a0

(class_data_bits_t *) $8 = 0x00000001000083a0

p $8->data() 查看 class_data_bits_t 里面的 data() 內(nèi)容

(class_rw_t *) $10 = 0x000000010066c030

p *$10 查看 class_rw_t 的內(nèi)容

(class_rw_t) $11 = {
  flags = 2148007936
  witness = 1
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = {
      Value = 4295000344
    }
  }
  firstSubclass = nil
  nextSiblingClass = 0x00007fff80103a88
}
1.4、以下是通過 class_rw_t 的源碼來查找類的屬 性內(nèi)容

class_rw_t 部分源碼

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint16_t witness;
#if SUPPORT_INDEXED_ISA
    uint16_t index;
#endif
    explicit_atomic<uintptr_t> ro_or_rw_ext;
    Class firstSubclass;
    Class nextSiblingClass;

    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 *>(&ro_or_rw_ext)->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
        }
    }
}

p $11.properties() 查看 properties 屬性

(const property_array_t) $12 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x0000000100008260
      }
      arrayAndFlag = 4295000672
    }
  }
}

p $12.list 查看 list里面的迭代器內(nèi)容

(const RawPtr<property_list_t>) $13 = {
  ptr = 0x0000000100008260
}

p $13.ptr 查看 ptr 地址

(property_list_t *const) $14 = 0x0000000100008260

p *$14 查看 ptr 的內(nèi)部結(jié)構(gòu)

(property_list_t) $15 = {
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}

p $15.get(0) 調(diào)用 get 方法獲取屬性值

(property_t) $16 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
1.5、屬性

探究:屬性列表存在于結(jié)構(gòu)體 class_ro_t

x/4gx Person.class 查看 Person 的元類信息

0x100008408: 0x0000000100008430 0x000000010036e140
0x100008418: 0x0000000100662570 0x0002802800000003

p/x 0x100008408+0x20 查看 class_data_bits_t 結(jié)構(gòu)體

(long) $1 = 0x0000000100008428

p (class_data_bits_t *)0x0000000100008428

(class_data_bits_t *) $2 = 0x0000000100008428

p $2->safe_ro()

(const class_ro_t *) $3 = 0x0000000100008188

查看源碼 class_ro_t 結(jié)構(gòu)體

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    union {
        const uint8_t * ivarLayout;
        Class nonMetaclass;
    };

    explicit_atomic<const char *> name;
    // With ptrauth, this is signed if it points to a small list, but
    // may be unsigned if it points to a big list.
    void *baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
    _objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
}

p *$3 查看 class_ro_t 結(jié)構(gòu)體

(const class_ro_t) $4 = {
  flags = 0
  instanceStart = 8
  instanceSize = 32
  reserved = 0
   = {
    ivarLayout = 0x0000000000000000
    nonMetaclass = nil
  }
  name = {
    std::__1::atomic<const char *> = "LGPerson" {
      Value = 0x0000000100003f4d "LGPerson"
    }
  }
  baseMethodList = 0x00000001000081d0
  baseProtocols = nil
  ivars = 0x0000000100008268
  weakIvarLayout = 0x0000000000000000
  baseProperties = 0x00000001000082d0
  _swiftMetadataInitializer_NEVER_USE = {}
}

p $3->ivars 查看 Person 類的屬性

(const ivar_list_t *const) $5 = 0x0000000100008268

p *$5 查看變量的具體信息

(const ivar_list_t) $6 = {
  entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 3)
}

p $6.get(0) 查看屬性

(ivar_t) $7 = {
  offset = 0x00000001000083a0
  name = 0x0000000100003e11 "hobby"
  type = 0x0000000100003f56 "@\"NSString\""
  alignment_raw = 3
  size = 8
}

2、內(nèi)存平移

// main.m
@interface Person : NSObject
{
    NSString *hobby;
    NSObject *objc;
}
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, strong) NSString *name;
@property (atomic, strong) NSString *aname;
+ (void)test;
- (void)test;
@end

@implementation Person
+ (void)test {}
- (void)test {}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [[Person alloc]init];
        p.name = @"KC";
        p.nickName = @"老師";
        p.aname = @"aNNN";
    }
    return 0;
}

以上是 main.m 的具體類結(jié)構(gòu)
使用命令編譯 main.m 文件
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
編譯后的屬性部分源碼

static NSString * _I_Person_nickName(Person * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_nickName)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_Person_setNickName_(Person * self, SEL _cmd, NSString *nickName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _nickName), (id)nickName, 0, 1); }

static NSString * _I_Person_name(Person * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_name)); }
static void _I_Person_setName_(Person * self, SEL _cmd, NSString *name) { (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_name)) = name; }

static NSString * _I_Person_aname(Person * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_aname)); }
static void _I_Person_setAname_(Person * self, SEL _cmd, NSString *aname) { (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_aname)) = aname; }
  • 具有 copy 的屬性,編譯后的結(jié)果中執(zhí)行 objc_setProperty 方法

查看objc 源碼

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
    if (offset == 0) {
        object_setClass(self, newValue);
        return;
    }

    id oldValue;
    id *slot = (id*) ((char*)self + offset);

    if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    } else {
        if (*slot == newValue) return;
        newValue = objc_retain(newValue);
    }

    if (!atomic) {
        oldValue = *slot;
        *slot = newValue;
    } else {
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }

    objc_release(oldValue);
}

void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) 
{
    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
    bool mutableCopy = (shouldCopy == MUTABLE_COPY);
    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}

void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}

void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, false, false, false);
}


void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, true, true, false);
}

void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, false, true, false);
}

最終調(diào)用 copyWithZone 方法

  • 沒有 copy 的屬性,直接執(zhí)行內(nèi)存平移

比如 (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_name)) = name;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容