在之前的幾篇博客里面息罗,已經(jīng)介紹了掂咒,類的底層結構,還有isa
的走位流程,元類的繼承鏈绍刮,對象方法温圆,類方法的存放位置,以及如何通過lldb
獲取成員和屬性孩革、對象方法岁歉,類方法。
本篇博客主要做一些補充和擴展膝蜈。
成員變量和屬性
開發(fā)年限比較久的iOS程序員锅移,都知道在iOS5
之前,經(jīng)潮ゲ看到一個大括號里面定義了成員變量非剃,同時用了@property
聲明,而且還在@implementation
中使用@synthesize
方法推沸。
其實备绽,發(fā)生這種狀況根本原因是蘋果將默認編譯器從GCC
轉換為LLVM
(low level virtual machine),才不再需要為屬性聲明實例變量了鬓催。
在沒有更改之前疯坤,屬性的正常寫法需要成員變量+ @property + @synthesize
成員變量三個步驟。 更換為LLVM
之后深浮,編譯器在編譯過程中發(fā)現(xiàn)沒有新的實例變量后,就會生成一個下劃線開頭的實例變量眠冈。因此現(xiàn)在我們不必在聲明一個實例變量飞苇。
現(xiàn)在@property
聲明的屬性不僅僅默認給我們生成一個_類型
的成員變量,同時也會生成setter/getter
方法蜗顽。
- 屬性 = 帶下劃線成員變量 + setter + getter ?法
- 實例變量 : 特殊的成員變量 (類的實例化)
從以上clang
底層源碼也可以驗證布卡,@property
聲明的屬性默認會生成一個_類型的成員變量,同時也會生成setter/getter
方法雇盖。
objc_setProperty
但是我們從上面的底層源碼發(fā)現(xiàn)了一個問題忿等,有的set
方法里面是通過objc_setProperty
獲取屬性,有的是通過內(nèi)存的平移崔挖。這是什么原因了呢贸街?通過對比不同屬性設置帶有copy
和不帶有copy
的底層源碼分析,可以找到原因是copy
這個設置的問題狸相!那么為驗證這個結論薛匪,我們?nèi)サ讓涌纯矗?/p>
LLVM
那我們?nèi)?code>llvm源碼里面看看,objc_setProperty
的實現(xiàn)邏輯脓鹃,你怎么就知道去llvm不是去objc源碼看呢逸尖?請看下圖分析
首先在底層也就是下層,蘋果的源碼是固定的,是不會改變的(這里的不變是指不會根據(jù)你代碼來改變娇跟,因為底層邏輯已經(jīng)寫好了)岩齿。在上層,我們程序開發(fā)人員苞俘,會寫很多中屬性盹沈,那么就會有各種各種的奇奇怪怪的代碼出現(xiàn),就有各種的
set
形式的代碼苗胀,比如setName襟诸、setAge、setXX
基协。歌亲。。等等澜驮。
這對編譯器來說陷揪,只是_cmd
的方法名字不一樣,那就需要一個中間層來把這些奇奇怪怪的杂穷,做一下處理悍缠,以便于和底層去交互,因為底層邏輯已經(jīng)封裝好耐量,不可能動態(tài)的改變的飞蚓。那我們?nèi)パ芯?code>objc_setProperty就不可能在運行時了,只能在編譯時了廊蜒,所以我們?nèi)ゾ?code>llvm里面看看趴拧!
那上層和objc_setProperty
之間有著怎樣的聯(lián)系呢?
我們在
llvm
里面找到了getGetPropertyFn
這個函數(shù)山叮,是獲取創(chuàng)建的CreateRuntimeFunction
著榴,里面有objc_setProperty
這個參數(shù)。那么為什么創(chuàng)建呢屁倔?繼續(xù)往下看看脑又,在哪里調用了既然調用了,肯定是有條件的锐借,是真的是是因為
property
的copy
嗎问麸?我們找到條件,就可以反推知道objc_setProperty
的作用了瞎饲。繼續(xù)往下看看看上面的代碼有沒有發(fā)現(xiàn)什么口叙?這有個屬性imp的策略
PropertyImplStrategy
,那么再繼續(xù)往下找看到?jīng)]有嗅战,如果
IsCopy
為真就Kind = GetSetProperty
妄田,這也就驗證了博客開篇的猜想俺亮,只有屬性里面用copy修飾的,才會有objc_setProperty
疟呐。
代碼獲取類的信息
iOS底層探索之類的結構(上)
iOS底層探索之類的結構(中)
在之前的博客里面脚曾,我們已經(jīng)知道了,可以在控制臺通過lldb
獲取類的信息启具,那么現(xiàn)在我們通過代碼來獲取下本讥。
class_copyMethodList
void lgObjc_copyMethodList(Class pClass){
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const method = methods[i];
//獲取方法名
NSString *key = NSStringFromSelector(method_getName(method));
LGLog(@"Method, name: %@", key);
}
free(methods);
}
class_getInstanceMethod
//獲取實例方法
void lgInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
class_getClassMethod
//獲取類方法
void lgClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
// - (void)sayHello;
// + (void)sayHappy;
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
class_getMethodImplementation
void lgIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));// 0
// sel -> imp 方法的查找流程 imp_farw
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy)); // 0
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
NSLog(@"%s",__func__);
}
代碼測試驗證
IMP,SEL
- SEL : 類成員方法的指針,但不同于C語言中的函數(shù)指針鲁冯,函數(shù)指針直接保存了方法的地址拷沸,但SEL只是方法編號。
- IMP:一個函數(shù)指針,保存了方法的地址
- SEL和IMP的關系就:SEL就相當于書本的?錄標題薯演,IMP就是書本的?碼撞芍,函數(shù)就是具體頁碼對應的內(nèi)容。
擴展
我們已經(jīng)學了這么多類的相關的知識了跨扮,那么我們看看下面這個面試題
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re3 = [(id)[JPPerson class] isKindOfClass:[JPPerson class]];
BOOL re4 = [(id)[JPPerson class] isMemberOfClass:[JPPerson class]];
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n,%hhd,%hhd",re1,re2,re3,re4,re9,re10);
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL re7 = [(id)[JPPerson alloc] isKindOfClass:[JPPerson class]];
BOOL re8 = [(id)[JPPerson alloc] isMemberOfClass:[JPPerson class]];
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
代碼運行結果
+ isKindOfClass
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- isKindOfClass
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
+ isMemberOfClass
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- isMemberOfClass
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- (Class)class {
return object_getClass(self);
}
分析
-
re1
傳入的是NSObject
的類序无,獲取元類
與NSObject
不等,繼續(xù)尋找獲取元類的父類為NSObject
與傳入的值相等衡创,返回true
- re2是
NSObject
類調用類方法isMemberOfClass
與NSObject類
比較帝嗡,很明顯,NSObject的元類
與NSObject
本身并不相等璃氢,所以返回false
-
re3
傳入的是JPPerson
的類哟玷,獲取元類
與JPPerson
不等,繼續(xù)尋找獲取元類的父類為NSObject
的元類一也,與傳入的值依舊不等碗降,繼續(xù)往上NSObject元類
的父類為NSObject
依舊不等,再往上就是nil
塘秦,最后返回false
-re4
是JPPerson
類調用類方法isMemberOfClass
與JPPerson類
比較,JPPerson的元類
與JPPerson
本身并不相等动看,所以返回false. -
re5
傳入的是NSObject
的實例尊剔,獲取對象的類,與NSObject
相等菱皆,返回true
-
re7
傳入的是JPPerson
的實例须误,獲取對象的類,與JPPerson
相等仇轻,返回true
-re8
是JPPerson
的實例調用實例方法isMemberOfClass
與JPPerson
類比較京痢,明顯的他們是相同的,所以返回true
更多內(nèi)容持續(xù)更新
?? 請動動你的小手篷店,點個贊????
?? 喜歡的可以來一波祭椰,收藏+關注臭家,評論 + 轉發(fā),以免你下次找不到我方淤,哈哈????
??歡迎大家留言交流钉赁,批評指正,互相學習??携茂,提升自我??