面試題1
分析以下代碼分別輸出什么饰躲?
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL re2 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];
BOOL re3 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL re4 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
BOOL re5 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL re6 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];
BOOL re7 = [(id)[NSObject alloc] isMemberOfClass:[NSObject 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);
}
return 0;
}
isKindOfClass
類方法isKindOfClass
該方法主要是用來(lái)判斷當(dāng)前類的元類
與條件類
是否相等嬉橙。
- 如果相等,返回YES祷肯;
- 如果不相等唯卖,則繼續(xù)查找
該元類的父類
粱玲,使之與條件類
進(jìn)行比較。
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
實(shí)例方法isKindOfClass
該方法主要是用來(lái)判斷當(dāng)前對(duì)象所屬的類
與條件類
是否相等拜轨。
- 如果相等抽减,則返回YES;
- 如果不相等橄碾,則繼續(xù)查找
該類的父類
卵沉,使之與條件類
進(jìn)行比較。
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
示例1
[(id)[NSObject class] isKindOfClass:[NSObject class]]
- 通過(guò)
[NSObject class]
分析得知法牲,調(diào)用的是類方法isKindOfClass
史汗。 - 第一次判斷
cls
為NSObject類
;
tcls
為NSObject元類
拒垃;
cls
不等于tcls
停撞。
修改tcls
為NSObject元類的父類
,即:NSObject類
悼瓮。 - 第二次判斷
cls
為NSObject類
戈毒;
tcls
為NSObject類
;
cls
等于tcls
横堡。
結(jié)果:返回YES
埋市。
示例2
[(id)[LGPerson class] isKindOfClass:[LGPerson class]]
- 通過(guò)
[LGPerson class]
分析得知,調(diào)用的是類方法isKindOfClass
命贴。 - 第一次判斷
cls
為LGPerson類
道宅;
tcls
為LGPerson元類
;
cls
不等于tcls
胸蛛。
修改tcls
為LGPerson元類的父類
污茵,即根元類NSObject
。 - 第二次判斷
cls
為LGPerson類
葬项;
tcls
為根元類
泞当;
cls
不等于tcls
。
修改tcls
為NSObject元類的父類
玷室,即:NSObject類
零蓉。 - 第三次判斷
cls
為LGPerson類
笤受;
tcls
為NSObject類
穷缤;
cls
不等于tcls
。
修改tcls
為NSObject類的父類
箩兽,即:nil
津肛。 - 由于
tcls
為nil
药版,循環(huán)結(jié)束堆缘。
結(jié)果:返回NO
;
示例3
[(id)[NSObject alloc] isKindOfClass:[NSObject class]]
- 通過(guò)
[NSObject alloc]
分析得知,調(diào)用的是對(duì)象方法isKindOfClass
十兢。 - 第一次判斷
cls
為NSObject類
;
tcls
為NSObject類
肺缕;
cls
等于tcls
狈涮。
結(jié)果:返回YES
。
示例4
[(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]
- 通過(guò)
[LGPerson alloc]
分析得知涯鲁,調(diào)用的是對(duì)象方法isKindOfClass
巷查。 - 第一次判斷
cls
為LGPerson類
;
tcls
為LGPerson類
抹腿;
cls
等于tcls
岛请。
結(jié)果:返回YES
。
isMemberOfClass
類方法isMemberOfClass
該方法主要用來(lái)判斷當(dāng)前類的元類
與條件類
是否相等警绩。
- 如果相等崇败,則返回YES;
- 如果不相等肩祥,則返回NO后室;
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
實(shí)例方法isMemberOfClass
該方法主要用來(lái)判斷當(dāng)前對(duì)象所屬的類
與條件類
是否相等。
- 如果相等搭幻,則返回YES咧擂;
- 如果不相等,則返回NO檀蹋;
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
示例5
[(id)[NSObject class] isMemberOfClass:[NSObject class]]
- 通過(guò)
[NSObject class]
分析得知松申,調(diào)用的是類方法isMemberOfClass
。 -
當(dāng)前元類
為NSObject元類
俯逾,條件類
為NSObject
贸桶。
結(jié)果:不相等
,返回NO
桌肴。
示例6
[(id)[LGPerson class] isMemberOfClass:[LGPerson class]]
- 通過(guò)
[LGPerson class]
分析得知皇筛,調(diào)用的是類方法isMemberOfClass
。 -
當(dāng)前元類
為LGPerson類的元類
坠七,條件類
為LGPerson類
水醋。
結(jié)果:不相等
,返回NO
彪置。
示例7
[(id)[NSObject alloc] isMemberOfClass:[NSObject class]]
- 通過(guò)
[NSObject alloc]
分析得知拄踪,調(diào)用的是實(shí)例方法isMemberOfClass
。 -
當(dāng)前對(duì)象類
為NSObject類
拳魁,條件類
為NSObject類
惶桐。
結(jié)果:相等
,返回YES
。
示例8
[(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]
- 通過(guò)
[LGPerson alloc]
分析得知姚糊,調(diào)用的是實(shí)例方法isMemberOfClass
贿衍。 -
當(dāng)前對(duì)象類
為LGPerson類
,條件類
為LGPerson類
救恨。
結(jié)果:相等
贸辈,返回YES
。
面試題1輸出結(jié)果:
2020-09-30 14:59:08.857321+0800 KCObjc[72747:9401735]
re1 :1
re2 :0
re3 :1
re4 :1
2020-09-30 14:59:12.976812+0800 KCObjc[72747:9401735]
re5 :0
re6 :0
re7 :1
re8 :1
Program ended with exit code: 0
總結(jié)
- 類方法 isKindOfClass 和 isMemberOfClass
相同:比較 元類 與條件類肠槽。
不同:isKindOfClass 在第一次比較不成功之后裙椭,會(huì)繼續(xù)查找元類的父類,直至找到nil署浩,而 isMemberOfClass 在比較不成功之后直接返回false揉燃。 - 實(shí)例方法 isKindOfClass 和 isMemberOfClass
相同:比較 類與 條件類
不同:isKindOfClass 在第一次比較不成功之后,會(huì)繼續(xù)查找類的父類筋栋,直至找到nil炊汤,而 isMemberOfClass 在比較不成功之后直接返回false。
面試題2
創(chuàng)建一個(gè) Person 類弊攘,繼承自 NSObject抢腐,分別添加一個(gè)實(shí)例方法和一個(gè)類方法
@interface LCPerson : NSObject
- (void)sayHello;
+ (void)say666;
@end
@implementation LCPerson
- (void)sayHello{
NSLog(@"sayHello");
}
+ (void)say666{
NSLog(@"say666");
}
@end
分析以下代碼分別輸出什么?
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
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));
NSLog(@"method1 :%p\n method2 :%p\n method3 :%p\n method4 :%p\n",method1,method2,method3,method4);
}
return 0;
}
class_getInstanceMethod
該方法主要是用于獲取實(shí)例方法
襟交,如果在傳入的類或者類的父類中沒(méi)有找到指定的實(shí)例方法迈倍,則返回NULL
。針對(duì)該方法捣域,蘋果有如下說(shuō)明
根據(jù)之前的分析啼染,
實(shí)例方法是存儲(chǔ)在對(duì)象所屬的類中
。
類方法是存儲(chǔ)元類中
焕梅。
分析
- method1
目的:在LGPerson類
中查找sayHello的實(shí)例方法
依據(jù):實(shí)例方法是存儲(chǔ)在對(duì)象所屬的類中
實(shí)際:在LGPerson類
中有定義sayHello的實(shí)例方法
結(jié)果:method1是存在的迹鹅。 - method2
目的:在LGPerson的元類
中查找sayHello的實(shí)例方法
依據(jù):實(shí)例方法是存儲(chǔ)在對(duì)象所屬的類中
實(shí)際:sayHello的實(shí)例方法
是存在LGPerson類
中
結(jié)果:method2是不存在的。 - method3
目的:在LGPerson類
中查找sayHappy的實(shí)例方法
依據(jù):實(shí)例方法是存儲(chǔ)在對(duì)象所屬的類中
實(shí)際:在LGPerson類
中沒(méi)有定義sayHappy的實(shí)例方法
結(jié)果:method3是不存在的贞言。 - method4
目的:在LGPerson的元類
中查找sayHappy的實(shí)例方法
依據(jù):實(shí)例方法是存儲(chǔ)在對(duì)象所屬的類中
實(shí)際:在LGPerson類
中沒(méi)有定義sayHappy的實(shí)例方法
斜棚,但是由于LGPerson類
定義了sayHappy的類方法
,而類方法
是以實(shí)例方法的形式
存儲(chǔ)在元類
中该窗。
結(jié)果:method4是存在的弟蚀。
面試題2輸出結(jié)果:
2020-09-30 15:01:41.051611+0800 KCObjc[72806:9404232]
method1 :0x100008100
method2 :0x0
method3 :0x0
method4 :0x100008098
Program ended with exit code: 0
面試題3
此題是對(duì)面試題2的延伸,因此準(zhǔn)備條件與面試題2一樣酗失。
分析以下代碼分別輸出什么义钉?
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
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));
NSLog(@"method1 :%p\n method2 :%p\n method3 :%p\n method4 :%p\n",method1,method2,method3,method4);
}
return 0;
}
class_getClassMethod
該方法主要是用于獲取類方法
,一個(gè)指向方法數(shù)據(jù)結(jié)構(gòu)的指針
级零,它指向類指定的類方法的實(shí)現(xiàn)
断医,如果指定的類或它的父類不包含具有指定的類方法,則為NULL
奏纪。針對(duì)該方法鉴嗤,蘋果有如下說(shuō)明
分析
Method class_getClassMethod(Class cls, SEL sel) {
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
由源碼知道,獲取類方法其實(shí)就是獲取元類的實(shí)例方法
序调。
method1
傳入的參數(shù)是LGPerson類
醉锅,但在class_getClassMethod
中,先根據(jù)LGPerson類
獲取LGPerson元類
发绢,然后再找LGPerson元類
中的實(shí)例方法sel
硬耍。此時(shí)sel
為sayHello方法
。
在LGPerson元類
中只存儲(chǔ)了sayHappy 方法
边酒。
結(jié)果:method1是不存在的经柴。method2
傳入的參數(shù)是LGPerson元類
,此時(shí)查找的是LGPerson元類
中的實(shí)例方法sel
墩朦。此時(shí)sel
為sayHello方法
坯认。
在LGPerson元類
中只存儲(chǔ)了sayHappy 方法
。
結(jié)果:method2是不存在的氓涣。method3
傳入的參數(shù)是LGPerson類
牛哺,但在class_getClassMethod
中,先根據(jù)LGPerson類
獲取LGPerson元類
劳吠,然后再找LGPerson元類
中的實(shí)例方法sel
引润。此時(shí)sel
為sayHappy方法
。
在LGPerson元類
中存儲(chǔ)了sayHappy 方法
痒玩。
結(jié)果:method3是存在的淳附。method4
傳入的參數(shù)是LGPerson元類
,此時(shí)查找的是LGPerson元類
中的實(shí)例方法sel
蠢古。此時(shí)sel
為sayHappy方法
燃观。
在LGPerson元類
中存儲(chǔ)了sayHappy 方法
。
結(jié)果:method4是存在的便瑟。
面試題3輸出結(jié)果:
2020-09-30 15:12:42.559984+0800 KCObjc[72925:9410227]
method1 :0x0
method2 :0x0
method3 :0x100008098
method4 :0x100008098
Program ended with exit code: 0
總結(jié)
實(shí)例方法存儲(chǔ)在對(duì)象所屬的類中
類方法存儲(chǔ)在元類中
在元類中缆毁,類方法是以實(shí)例方法的形式存儲(chǔ)的
對(duì)象是所屬類的實(shí)例
類是元類的實(shí)例