1. 下面的代碼輸出什么內(nèi)容?
@interface LGPerson : NSObject
- (void)sayHello;
+ (void)sayHappy;
@end
@implementation LGPerson
- (void)sayHello{
NSLog(@"LGPerson say : Hello!!!");
}
+ (void)sayHappy{
NSLog(@"LGPerson say : Happy!!!");
}
@end
1.1
void lgInstanceMethod_classToMetaclass(Class pClass){
// 其中pClass中sayHello定義為實(shí)例方法,sayHappy定義為類方法
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);
}
解答:根據(jù)之前的學(xué)習(xí)我們知道其實(shí)并不存在什么類方法,類方法就是元類的實(shí)例方法,所以答案是:0xXXXXXXX-0x0-0x0-0xXXXXXXXX。
1.2
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);
}
解答:此題的難點(diǎn)在于class_getClassMethod的背后的實(shí)現(xiàn)原理。有下面的實(shí)現(xiàn)代碼可知class_getClassMethod其實(shí)就是找了傳入的cls的元類再調(diào)用class_getInstanceMethod函數(shù),這里面還有一個(gè)坑點(diǎn)在于getMeta函數(shù)的實(shí)現(xiàn),在調(diào)用getMeta函數(shù)時(shí)會(huì)先判斷當(dāng)前傳入的類是否是元類,如果是直接返回當(dāng)前類,如果不是則通過isa返回元類。所以不論怎樣都會(huì)返回正確的元類。所以本題的答案是:0x0-0x0-0xXXXXXXXX-0xXXXXXXX。
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
Class getMeta() {
if (isMetaClassMaybeUnrealized()) return (Class)this;
else return this->ISA();
}
1.3
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));
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
NSLog(@"%s",__func__);
}
此題的難點(diǎn)還是在于函數(shù)的實(shí)現(xiàn),imp1和imp4毫無疑問肯定可以找到對應(yīng)的實(shí)現(xiàn),但是當(dāng)當(dāng)前類沒有對應(yīng)實(shí)現(xiàn)的時(shí)候會(huì)返回默認(rèn)的消息轉(zhuǎn)發(fā)實(shí)現(xiàn)_objc_msgForward
__attribute__((flatten))
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
lockdebug_assert_no_locks_locked_except({ &loadMethodLock });
imp = lookUpImpOrNilTryCache(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward;
}
return imp;
}
2. iskindOfClass & isMemberOfClass 的理解
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- iskindOfClass & isMemberOfClass 類方法調(diào)用
//-----使用 iskindOfClass & isMemberOfClass 類方法
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);
解答:
isKindOfClass的類方法實(shí)現(xiàn)會(huì)以當(dāng)前類的元類為初始值和傳入的類進(jìn)行比較,如果相同則返回YES,如果不相等則不停的取當(dāng)前類的元類的superclass與傳入的類進(jìn)行比較,如果相等則返回YES,如果一直到nil都沒有相等則返回NO。
isMemberOfClass的類方法實(shí)現(xiàn)則是判斷當(dāng)前類的元類是否等于傳入類,如果相等返回YES,如果不相等返回NO。
當(dāng)傳入的類不是元類時(shí),進(jìn)行類方法的調(diào)用,isKindOfClass只有NSObject才會(huì)返回YES,isMemberOfClass則永遠(yuǎn)不會(huì)返回YES。故本題的答案是1-0-0-0。
- iskindOfClass & isMemberOfClass 實(shí)例方法調(diào)用
//------iskindOfClass & isMemberOfClass 實(shí)例方法
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);
解答:
isKindOfClass的實(shí)例方法實(shí)現(xiàn)會(huì)以當(dāng)前實(shí)例的類為初始值和傳入的類進(jìn)行比較,如果相同則返回YES,如果不相等則不停的取當(dāng)前實(shí)例的類的superclass與傳入的類進(jìn)行比較,如果相等則返回YES,如果一直到nil都沒有相等則返回NO,簡單來說就是判斷當(dāng)前實(shí)例是否是傳入類及其所有子類的實(shí)例。
isMemberOfClass的類方法實(shí)現(xiàn)則是判斷當(dāng)前實(shí)例的類是否等于傳入類,如果相等返回YES,如果不相等返回NO。
故此題的答案是1-1-1-1。
總結(jié)
isKindOfClass
類方法:元類->父元類->...->根源類->根類與傳入的類進(jìn)行比較,有一個(gè)相等則返回YES,沒有則返回NO。
實(shí)例方法:類->父類->...->根類與傳入的類進(jìn)行比較,有一個(gè)相等則返回YES,沒有則返回NO。isMemberOfClass
類方法:元類與傳入的類進(jìn)行比較,相等則返回YES,不相等則返回NO。
實(shí)例方法:類與傳入的類進(jìn)行比較,相等則返回YES,不相等則返回NO。