美文网首页APP & program
[iOS]2、类的原理

[iOS]2、类的原理

作者: 史记_d5da | 来源:发表于2022-02-26 15:05 被阅读0次

1、class的底层结构探究

通过如下代码进行 class 的结构调试

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

补充:
1、objc_class 继承自 objc_object
2、pobjc_class 对象,Person 对象为 objc_object结构体
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;
}

从类的结构中分析得知,前 8 个字节为 isa, 后 8 个字节为 superclass
控制台操作:
x/4gx Person.class Person 元类的内存结构

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

po 0x00000001000083a8 第一个 8 个字节(isa)打印结果

Person

po 0x000000010036e140 第二个 8个字节(superclass)打印结果

NSObject
1.2、cache_t

cache_t 的结构体如下

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 为泛型结构,大小为泛型的类型
cache_t 结构体的大小为 16 个字节

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 个字节处
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() 内容

(class_rw_t *) $10 = 0x000000010066c030

p *$10 查看 class_rw_t 的内容

(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 的源码来查找类的属 性内容

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里面的迭代器内容

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

p $13.ptr 查看 ptr 地址

(property_list_t *const) $14 = 0x0000000100008260

p *$14 查看 ptr 的内部结构

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

p $15.get(0) 调用 get 方法获取属性值

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

探究:属性列表存在于结构体 class_ro_t

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

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

p/x 0x100008408+0x20 查看 class_data_bits_t 结构体

(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 结构体

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 结构体

(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、内存平移

// 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 的具体类结构
使用命令编译 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 的属性,编译后的结果中执行 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);
}

最终调用 copyWithZone 方法

  • 没有 copy 的属性,直接执行内存平移

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

相关文章

网友评论

    本文标题:[iOS]2、类的原理

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