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 是否為傳進來類的類或者子類
