目标的分类

Object- C中一切目标能够分为3类,实例目标,类目标,元类目标。其间我们开发者常用的承继自NSObject都归于实例目标,实例目标经过isa指针指向的是类目标。类目标经过isa指向的是元类目标。类目标和元类目标拥有相同的结构,都是来自objc_class

objc_class结构

在objc4源码中查找objc_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
}

其间isa指针式其承继自objc_object的。本文主要解说类结构中的isasuperclassbitscache的内容单放一篇。

isa在之前的内容里边现已讲过,主要是指向类目标或者元类目标的。 superclass是体现出承继联系的。 cache是办法缓存。 bits是类的其他信息,例如成员变量,办法列表,协议,特点。

留意:元类目标结构也是如此,但元类目标里边没有成员变量,协议,特点这些内容。

isa指向图

相信做iOS开发都必须掌握的一个图。

iOS八股文(三)类对象的结构(上)

这儿对isa指向做一个简略的总结

实例目标的isa指针指向对应的类目标,类目标的isa指针指向对应的元类目标,元类目标的isa指向基类的元类目标(根元类)。

能够简略的用lldb调试来验证一下。

- (void)test {
  // 
  NSObject *objc = [[NSObject alloc] init];
    //isa指向的就是类目标
  Class objcClass1 = [NSObject class];
  Class objcMetaClass = object_getClass([NSObject class]);
}

iOS八股文(三)类对象的结构(上)
先获取objcisa指针的值,然后用这个值与运算ISA_MASK,得到的值,正好是类目标的地址。

iOS八股文(三)类对象的结构(上)
然后用相同的办法获取类目标的值,和ISA_MASK与运算得到元类目标的地址。

能够持续这样再操作一轮,得到的还是元类目标的地址。这是由于该类是NSObjectNSObject元类目标的isa是指向自己的(图中右上交的循环箭头)。

iOS八股文(三)类对象的结构(上)
这儿由于0x00000001d64226c0的高9位和低3位都是0所以没有做与运算,结果其实是相同的。 留意ISA_MASK的使用需要留意环境,我这儿是M1的模拟器。

superClass指向

superClass的指向也在上面那个经典的图中。这儿要留意superclassobjc_class才有的,所以实例目标是没有的。类目标的superclass指向父类目标,元类目标的superclass指向父类的元类目标,根元类目标的superclass指针指向 根类目标。根类目标的superclassnil

留意:根元类目标的superclass指针指向 根类目标,这个是有一个面试题的。 请听题:

@interface NSObject (Interview)
+ (void)foo;
@end
@implementation NSObject (Interview)
//能经过这个调用的原因是,NSObject的基元类的supclass为NSobject的元类
- (void)foo {
 NSLog(@"IMP: -[NSObject foo]");
}
@end
- (void)test {
    [NSObject foo];
}

上面的代码能执行成功么?这题要结合objc_msgSend一起看,调查的点就是根元类目标的superclass指针指向根类目标。

bits

类的结构中还有一个bits,里边也存了很多信息,我们先看bits的数据结构 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);
  }
    // Get the class's ro data, even in the presence of concurrent realization.
  // fixme this isn't really safe without a compiler barrier at least
  // and probably a memory barrier when realizeClass changes the data field
  const class_ro_t *safe_ro() const {
    class_rw_t *maybe_rw = data();
    if (maybe_rw->flags & RW_REALIZED) {
      // maybe_rw is rw
      return maybe_rw->ro();
    } else {
      // maybe_rw is actually ro
      return (class_ro_t *)maybe_rw;
    }
  }
}

其实最最重要的是其间的2个办法。datasafe_ro,两个办法分别返回class_rw_tclass_ro_t

这儿ro_t的获取也是经过data办法获取的,一切能够理解为ro_t也在rw_t之中。

class_rw_t

持续来看class_rw_t的数据结构。

iOS八股文(三)类对象的结构(上)
rw_t中能够 看到有这3个办法,经过这三个办法分别能获取到类的办法、特点、协议。

class_ro_t

再看class_ro_t的数据结构。

iOS八股文(三)类对象的结构(上)

iOS八股文(三)类对象的结构(上)

能够看到有办法、特点、协议和成员变量。但办法、特点、协议的命名都是base注册的。