上篇分析類結(jié)構(gòu)蜡感,獲取到了屬性列表 property_array_t
和方法列表 method_array_t
呻待。
實(shí)踐代碼:
@interface GLPerson : NSObject
@property (nonatomic, strong) NSString *name; /**< 8個(gè)字節(jié) */
@property (nonatomic, strong) NSString *nickName; /**< 8個(gè)字節(jié) */
- (void)sayHello;
+ (void)goSchool;
@end
@interface GLStudent : GLPerson
@end
一、類的類方法存儲(chǔ)
通過源碼查看趁怔,沒有看到底層把 method
區(qū)分類方法還是實(shí)例方法湿硝。既然實(shí)例方法存在類對(duì)象中薪前,類方法是不是可能存在元類中。試著通過 lldb
打印一下关斜。
(lldb) x/4gx GLPerson.class
0x1000022b8: 0x0000000100002290 0x0000000100333140
0x1000022c8: 0x000000010113f640 0x0001802400000003
(lldb) p 0x0000000100002290 & 0x00007ffffffffff8ULL // 通過isa找到元類
(unsigned long long) $1 = 4294976144
(lldb) x/4gx $1 // 讀取元類的內(nèi)存
0x100002290: 0x00000001003330f0 0x00000001003330f0
0x1000022a0: 0x0000000100643250 0x0001e03500000007
(lldb) p (class_data_bits_t *)0x1000022b0 // 通過偏移32字節(jié)獲取class_data_bits_t指針
(class_data_bits_t *) $2 = 0x00000001000022b0
(lldb) p *$2->data() // 調(diào)用class_data_bits_t 的data方法獲取class_rw_t
(class_rw_t) $3 = {
flags = 2684878849
witness = 1
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = 4294975528
}
firstSubclass = 0x00000001000022e0
nextSiblingClass = 0x00007fff88bf1948
}
(lldb) p $3.methods() // 打印元類的方法列表
(const method_array_t) $4 = {
list_array_tt<method_t, method_list_t> = {
= {
list = 0x0000000100002070
arrayAndFlag = 4294975600
}
}
}
(lldb) p $4.list
(method_list_t *const) $5 = 0x0000000100002070
(lldb) p *$5
(method_list_t) $6 = {
entsize_list_tt<method_t, method_list_t, 3> = {
entsizeAndFlags = 26
count = 1
first = {
name = "goSchool"
types = 0x0000000100000f7c "v16@0:8"
imp = 0x0000000100000d70 (`+[GLPerson goSchool])
}
}
}
(lldb) p $6.get(0) // 第一個(gè)就是聲明的類方法
(method_t) $7 = {
name = "goSchool"
types = 0x0000000100000f7c "v16@0:8"
imp = 0x0000000100000d70 (`+[GLPerson goSchool])
}
(lldb) p $6.get(1) // 只有一個(gè)類方法示括,下一個(gè)越界了
Assertion failed: (i < count), function get, file /Users/xulong/Desktop/學(xué)習(xí)/alloc流程分析/runtime/objc-runtime-new.h, line 438.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
通過上面代碼發(fā)現(xiàn):
- 方法存儲(chǔ)的時(shí)候是沒有明確的區(qū)分是類方法還是實(shí)例方法的;
- 實(shí)例方法存儲(chǔ)在類的數(shù)據(jù)中痢畜;
- 類方法存儲(chǔ)在元類的數(shù)據(jù)中例诀;
1.1 通過runtime源碼分析
runtime
里面有方法:
-
class_getInstanceMethod
: 返回一個(gè)類的指定實(shí)例方法; -
class_getClassMethod
:返回一個(gè)類的指定類方法裁着;
const char *className = class_getName([GLPerson class]);
Class metaClass = objc_getMetaClass(className);
Method instanceM1 = class_getInstanceMethod([GLPerson class], @selector(sayHello));
Method instanceM2 = class_getInstanceMethod([GLPerson class], @selector(goSchool));
Method classM1 = class_getClassMethod([GLPerson class], @selector(sayHello));
Method classM2 = class_getClassMethod([GLPerson class], @selector(goSchool));
Method metaInstanceM1 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method metaInstanceM2 = class_getInstanceMethod(metaClass, @selector(goSchool));
Method metaClassM1 = class_getClassMethod(metaClass, @selector(sayHello));
Method metaClassM2 = class_getClassMethod(metaClass, @selector(goSchool));
NSLog(@"instanceM1:%p; instanceM2:%p; classM1:%p; classM2:%p;", instanceM1, instanceM2, classM1, classM2);
NSLog(@"metaInstanceM1:%p; metaInstanceM2:%p; metaClassM1:%p; metaClassM2:%p;", metaInstanceM1, metaInstanceM2, metaClassM1, metaClassM2);
console: instanceM1:0x1000020f8; instanceM2:0x0; classM1:0x0; classM2:0x100002090;
console: metaInstanceM1:0x0; metaInstanceM2:0x1000020a0; metaClassM1:0x0; metaClassM2:0x1000020a0;
分析一下
第一行類輸出:代表類有無
-
instanceM1
有值: 有sayHello
實(shí)例方法繁涂,instanceM2
沒值: 沒有goSchool
實(shí)例方法; -
classM1
沒值:沒有sayHello
類方法二驰,classM2
有值:有goSchool
類方法扔罪;
第二行元類輸出:代表元類有無
-
metaInstanceM1
沒值: 沒有sayHello
實(shí)例方法,metaInstanceM2
有值: 有goSchool
實(shí)例方法桶雀; -
metaClassM1
沒值:沒有sayHello
類方法矿酵,metaClassM2
有值:有goSchool
類方法;
這里先看下 class_getClassMethod
的源碼:
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
---
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
class_getClassMethod
的流程:
-
class_getClassMethod
里面調(diào)用的也是class_getInstanceMethod
; - 只不過傳的類是
cls->getMeta()
這個(gè)方法返回的; -
getMeta
如果是元類矗积,返回的就是自己全肮; -
getMeta
如果不是元類,返回的是ISA()
; - 類的
ISA()
返回的是 該類的元類;
class_getClassMethod總結(jié):
- 如果傳的類棘捣,里面是獲取的元類的
class_getInstanceMethod
方法辜腺。也既類方法是從元類里面去找的。 - 如果傳的是元類乍恐,直接用元類調(diào)用
class_getInstanceMethod
方法评疗。
二、是不是這個(gè)類 isKindOfClass & isMemberOfClass
首先有這樣一段代碼:
BOOL obClass_k = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //
BOOL obClass_m = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //
BOOL peClass_k = [(id)[GLPerson class] isKindOfClass:[GLPerson class]]; //
BOOL peClass_m = [(id)[GLPerson class] isMemberOfClass:[GLPerson class]]; //
NSLog(@"\n obClass_k :%hhd\n obClass_m :%hhd\n peClass_k :%hhd\n peClass_m :%hhd\n",obClass_k, obClass_m, peClass_k, peClass_m);
BOOL obInstance_k = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL obInstance_m = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL peInstance_k = [(id)[GLPerson alloc] isKindOfClass:[GLPerson class]]; //
BOOL peInstance_m = [(id)[GLPerson alloc] isMemberOfClass:[GLPerson class]]; //
NSLog(@"\n obInstance_k :%hhd\n obInstance_m :%hhd\n peInstance_k :%hhd\n peInstance_m :%hhd\n",obInstance_k, obInstance_m, peInstance_k, peInstance_m);
console
:
obClass_k :1
obClass_m :0
peClass_k :0
peClass_m :0
---
obInstance_k :1
obInstance_m :1
peInstance_k :1
peInstance_m :1
可找到上面調(diào)用的具體源碼如下:
// 類方法調(diào)用
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
// 實(shí)例方法調(diào)用
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
但是在實(shí)際調(diào)用的時(shí)候茵烈,斷點(diǎn)發(fā)現(xiàn) isKindOfClass 沒有走到 上面的源碼中百匆,通過匯編查看下具體走的什么方法
發(fā)現(xiàn)調(diào)用的是objc_opt_isKindOfClass
,what !!!
呜投,猜測應(yīng)該是蘋果再 llvm
編譯時(shí)期做了操作加匈。
// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
for (Class tcls = cls; tcls; tcls = tcls->superclass) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
-
分析1
[(id)[NSObject class] isKindOfClass:[NSObject class]];
:-
[NSObject class]
返回類自己; -
objc_opt_isKindOfClass
中,obj
為NSObject
類仑荐,otherClass
為NSObject
類雕拼; -
Class cls
首先賦值為NSObject
的元類; -
Class tcls = cls
,tcls
賦值元類释漆,判斷tcls
是否等于otherClass
悲没,類不等于元類; - 把
tcls = tcls->superclass
,NSObject
元類的superclass
為根類示姿,也就是[NSObject class]
甜橱; -
tcls
現(xiàn)在為NSObject
類,所以和otherClass
相等栈戳; - 返回
YES
岂傲;
-
-
分析2
[(id)[NSObject class] isMemberOfClass:[NSObject class]]
:-
[NSObject class]
返回類自己,所以會(huì)調(diào)用類方法; -
self
和cls
都為NSObject
類子檀; -
self->ISA()
返回NSObject
的元類镊掖; -
NSObject
的元類和類不相等; - 返回
NO
褂痰;
-
-
分析3
[(id)[GLPerson class] isKindOfClass:[GLPerson class]]
:-
[GLPerson class]
返回類自己亩进,所以會(huì)調(diào)用類方法; -
objc_opt_isKindOfClass
中,obj
為GLPerson
類缩歪,otherClass
為GLPerson
類归薛; -
Class cls
和Class tcls
首先賦值為GLPerson
的元類; -
tcls
存在,判斷tcls
是否等于otherClass
匪蝙,類不等于元類主籍; - 把
tcls = tcls->superclass
,GLPerson
元類的superclass
為根元類逛球,也就是[NSObject class]
的元類千元; -
tcls
現(xiàn)在為NSObject
元類,不等于otherClass
的GLPerson
類颤绕; - 再次把
tcls = tcls->superclass
幸海,NSObject
元類的superclass
為[NSObject class]
類; -
tcls
為NSObject
類 不等于otherClass
的GLPerson
類屋厘; - 再再次
tcls = tcls->superclass
涕烧,NSObject
類的superclass
為nil
; -
tcls
為nil
; - 返回
NO
汗洒;
-
-
分析4
[(id)[GLPerson class] isMemberOfClass:[GLPerson class]]
:-
[GLPerson class]
返回類自己,所以會(huì)調(diào)用類方法; -
self
和cls
都為GLPerson
類父款; -
self->ISA()
返回GLPerson
的元類溢谤; -
GLPerson
的元類和類不相等; - 返回
NO
憨攒;
-
-
分析5
[(id)[NSObject alloc] isKindOfClass:[NSObject class]]
:-
[NSObject alloc]
是實(shí)例世杀; -
Class cls = obj->getIsa()
,cls
賦值為NSObject
類肝集; -
Class cls
和tcls
賦值為NSObject
類瞻坝,otherClass
賦值為NSObject
類;cls
為[NSObject class]
杏瞻; - 所以
tcls
等于otherClass
所刀,都是NSObject
類衙荐; - 返回
YES
;
-
-
分析6
[(id)[NSObject alloc] isMemberOfClass:[NSObject class]]
:-
[NSObject alloc]
是實(shí)例,所以會(huì)調(diào)用實(shí)例方法浮创; -
[self class]
為 NSObject 類忧吟,cls
為[NSObject class]
; - 都是
NSObject
類斩披; - 返回
YES
;
-
-
分析7
[(id)[GLPerson alloc] isKindOfClass:[GLPerson class]]
:-
[GLPerson alloc]
是實(shí)例溜族; -
Class cls = obj->getIsa()
,cls
賦值為GLPerson
類垦沉; -
Class cls
和tcls
賦值為GLPerson
類煌抒,otherClass
為GLPerson
類; - 所以
tcls
等于otherClass
厕倍,都是GLPerson
類摧玫; - 返回
YES
;
-
-
分析8
[(id)[GLPerson alloc] isMemberOfClass:[GLPerson class]]
:-
[GLPerson alloc]
是實(shí)例,所以會(huì)調(diào)用實(shí)例方法绑青; -
[self class]
為 GLPerson 類诬像,cls
為[GLPerson class]
; - 都是
GLPerson
類闸婴; - 返回
YES
;
-