一、類方法為什么存在元類中
首先,我們?cè)?code>LGPerson中定義兩個(gè)方法想暗,一個(gè)實(shí)例方法
麻敌,一個(gè)類方法
:
@interface LGPerson : NSObject
- (void)sayHello;
+ (void)sayHappy;
@end
并且在main.m
中定義了幾個(gè)函數(shù):
1栅炒、lgObjc_copyMethodList
函數(shù):獲取方法列表
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);
}
2、lgInstanceMethod_classToMetaclass
函數(shù):獲取實(shí)例方法
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);
}
3、lgClassMethod_classToMetaclass
函數(shù):獲取類方法
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));
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);
}
我們?cè)?code>main函數(shù)中調(diào)用上面相關(guān)函數(shù)
:
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
lgObjc_copyMethodList(pClass);
lgInstanceMethod_classToMetaclass(pClass);
lgClassMethod_classToMetaclass(pClass);
}
return 0;
}
打印結(jié)果如下:
Method, name: sayHello
lgInstanceMethod_classToMetaclass - 0x1000031b0-0x0-0x0-0x100003148
lgClassMethod_classToMetaclass-0x0-0x0-0x100003148-0x100003148
在獲取實(shí)例方法
中赢赊,method1:0x1000031b0
乙漓、method2:0x0
、method3:0x0
释移、method4:0x100003148
叭披,其中method1
和method4
表示找到方法,method2
和method3
表示未找到方法玩讳。
我們進(jìn)入lgInstanceMethod_classToMetaclass
中看到涩蜘,pClass
是我們傳入的LGPerson類
,metaClass
是通過pClass
獲取到的LGPerson元類
熏纯。
通過method1
和method2
同诫,我們可以看出實(shí)例方法
存在類
中(LGPerson類
中確實(shí)聲明了一個(gè)sayHello
方法),通過method3
和method4
樟澜,我們可以看出類方法
存在元類
中误窖,但是method4
通過獲取實(shí)例方法
為什么能得到sayHappy
這個(gè)類方法
呢?
我們看一下lgClassMethod_classToMetaclass
秩贰,通過method3
和method4
霹俺,我們的可以看出類
和元類
都有sayHappy
這個(gè)類方法
,不是說類方法
存在元類
中嗎萍膛?怎么類
中也會(huì)有呢吭服?
這里我們來看下class_getClassMethod
的源碼實(shí)現(xiàn):
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
發(fā)現(xiàn)其中實(shí)現(xiàn)的還是獲取實(shí)例方法
,只是其中多了一個(gè)cls->getMeta()
蝗罗,我們繼續(xù)看下其源碼:
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
可以看到這里有一個(gè)判斷:判斷傳進(jìn)來
的是不是元類
艇棕,是的話直接返回
,不是的話就根據(jù)isa
返回元類
串塑。這里就很好的解釋了剛剛上面的兩個(gè)疑問了沼琉。
總結(jié)
1、實(shí)例方法
存在類
中
2桩匪、類方法
存在元類
中
3打瘪、獲取類方法
的本質(zhì)
是獲取元類
的實(shí)例方法
二、isKindOfClass & isMemberOfClass
剛剛我們探究了實(shí)例方法
以及類方法
傻昙,同樣的這兩個(gè)方法也存在實(shí)例方法
和類方法
闺骚,那它們有什么不同呢?我們先來輸出打印下:
1妆档、isKindOfClass & isMemberOfClass 類方法調(diào)用
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
打印結(jié)果:
re1 :1
re2 :0
re3 :0
re4 :0
首先是+ (BOOL)isKindOfClass:(Class)cls
的源碼:
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
結(jié)合示例與源碼我們來看一下:
re1(NSObject)
:首先是獲取元類tcls
僻爽,所以tcls
為根元類
,然后根元類
與cls(這里是NSObject類)
比較贾惦,肯定是不相等的胸梆,繼續(xù)循環(huán)敦捧,tcls
指向它的父類
,我們知道根元類
的父類
是NSObject
碰镜,即tcls
這時(shí)等于NSObject
兢卵,滿足tcls == cls
,返回YES
re3(LGPerson)
:先是tcls
為LGPerson元類
與LGPerson類
進(jìn)行比較绪颖,不相等后繼續(xù)循環(huán)秽荤,根據(jù)superclass
走向圖,tcls
最終是走向nil
菠发,tcls == cls
永不成立王滤,返回NO
再來是+ (BOOL)isMemberOfClass:(Class)cls
的源碼:
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
可以看到,這里直接是元類
與類
進(jìn)行比較滓鸠,re2(NSObject)
和re4(LGPerson)
條件永不成立雁乡,返回NO
2、isKindOfClass & isMemberOfClass 實(shí)例方法調(diào)用
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
打印結(jié)果:
re5 :1
re6 :1
re7 :1
re8 :1
首先是- (BOOL)isKindOfClass:(Class)cls
的源碼:
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
結(jié)合示例與源碼我們來看一下:
可以看到這里是獲取對(duì)象的類
與傳入的類
進(jìn)行比較糜俗,相等則返回YES
踱稍,不等則繼續(xù)循環(huán)tcls
指向superclass
再比較,循環(huán)結(jié)束還不成立悠抹,返回NO
珠月,這里re5(NSObject)
和re7(LGPerson)
條件恒成立,返回YES
再來是- (BOOL)isMemberOfClass:(Class)cls
的源碼:
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
可以看到楔敌,這里只有對(duì)象的類
與傳入的類
進(jìn)行比較啤挎,成立返回YES
,不成立返回NO
卵凑,這里re6(NSObject)
和re8(LGPerson)
條件恒成立庆聘,返回YES
總結(jié)
1、isKindOfClass
類方法:元類
--->根元類
--->根類
--->nil
與傳入的類
比較
實(shí)例方法:類
---> 父類
---> 根類
---> nil
與傳入的類
比較
2勺卢、isMemberOfClass
類方法:元類
與傳入的類
比較
實(shí)例方法:類
與傳入的類
比較