super(二) 以及内存分布
- 2019 年 10 月 8 日
- 筆記
一、练习
定义一个Person类
@interface Person : NSObject @property (nonatomic, strong) NSString *age; - (void)test; @end @implementation Person - (void)test{ NSLog(@"age = %@",self.age); }
ViewController 继承自UIViewController
在ViewController 书写以下代码。问是否能编译通过,如果可以输出什么是什么?
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. id cls = [Person class]; void * temp = &cls; [(__bridge id)temp test]; Person *per = [[Person alloc] init]; [per test]; }
运行结果
age = <ViewController: 0x7fb25241d9c0> age = (null)
分析
1. [super viewDidLoad]
product -> Preform Action-> assemble 查看中间层代码
.loc 1 18 5 prologue_end ## /Users/iOS/Desktop/Demo/Demo/ViewController.m:18:5 movq -8(%rbp), %rsi movq %rsi, -32(%rbp) movq L_OBJC_CLASSLIST_SUP_REFS_$_(%rip), %rsi movq %rsi, -24(%rbp) movq L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi leaq -32(%rbp), %rdi callq _objc_msgSendSuper2
其实super 底层实现的是_objc_msgSendSuper2
而不是上一篇文章的 _objc_msgSendSuper
两个还是有区别的。我们先看一下_objc_msgSendSuper
传参
// rewrite-objc 结果 _objc_msgSendSuper( struct { id self Class superClass },@selector(viewDidLoad) ) // 底层实现 汇编结果 _objc_msgSendSuper2( struct { id receiver Class current_class },@selector(viewDidLoad) )
通过assemble生成的中间代码可以看出调用的是_objc_msgSendSuper2
在源码中也有对_objc_msgSendSuper2
的参数介绍
ENTRY _objc_msgSendSuper2 UNWIND _objc_msgSendSuper2, NoFrame ldp p0, p16, [x0] // p0 = real receiver, p16 = class ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass CacheLookup NORMAL END_ENTRY _objc_msgSendSuper2
从源码中 可以看到 传入参数为第一个为接收者(self) 第二个参数为 [current class]
ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
在上面这句代码中 获取到当前class 的superclass
2.viewDidLoad中的内存分配

我们先看图下面区域
蓝色区域为person的实例变量。per指向person实例变量
而我们的对象方法存储在class中,所以通过指针找到per ->isa -> class ->方法列表 ->具体方法
我们再看图上面区域
蓝色区域为cls变量 temp指向cls cls指向person class
从图中我们可以看出,两个在内存结构几乎一致。
我们知道 c中是通过地址与指针找到对象。可以触发person的对象方法
既然是地址寻找。那当我们调用age属性的时候,正常走的是person实例变量的地址。而在temp中,这个地址为
self,所以temp中调用的age为viewcontroller 因为他们在相同的内存位置。
二、从源码的角度看isMemberOfClass和isKindOfClass
+ (BOOL)isMemberOfClass:(Class)cls { // 当类传进来的时候 获取的是mate-class return object_getClass((id)self) == cls; } - (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; } + (BOOL)isKindOfClass:(Class)cls { for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) { // 循环遍历父类 直到nil 或者相等 if (tcls == cls) return YES; } return NO; } - (BOOL)isKindOfClass:(Class)cls { for (Class tcls = [self class]; tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; }
结论
当类方法object_getClass(self) == mate-class
- isMemberOfClass 当前对象的class是等于传进来的class
- isKindOfClass 是否为传进来类的类或者子类