isMemberOfClass、isKindOfClass原理分析

這酸爽!發表於2019-07-31

isMemberOfClass

- 呼叫者必須是傳入的類的例項物件才返回YES
- 判斷呼叫者是否是傳入物件的例項,別弄反了,如 [s1 isMemberOfClass:p1] ,意思是s1是否是p1的例項物件
- 去去父類遞迴查詢判斷

原始碼:

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

有兩個方法,一個類方法,一個物件方法,兩者區別:

 - 例項方法:是根據例項物件取得類物件,再去判斷
 - 物件方法:是根據物件取得元類物件,再去判斷

例項程式碼:

XPerson* p1 = [[XPerson alloc]init];
XStudent* s1 = [[XStudent alloc]init];

// true (用s1的類物件和 [s1 class] 判斷,肯定是一樣的了)
NSLog(@"s1是否是s1 例項: %i",[s1 isMemberOfClass:[s1 class]]);
// true ([s1 class] 與 [XStudent class] 等同,一個類只會有一個類物件,一個元類物件,可以有多個例項物件)
NSLog(@"s1是否是XStudent 例項: %i",[s1 isMemberOfClass:[XStudent class]]);
// false (s1的類物件 != p1的類物件)
NSLog(@"s1是否是p1 例項: %i",[s1 isMemberOfClass:[p1 class]]);
// false (同上)
NSLog(@"s1是否是XPerson 例項: %i",[s1 isMemberOfClass:[XPerson class]]);

// false (XStudent元類物件 != XStudent類物件)(底層是獲取XStudent的元類去比較)
NSLog(@"XStudent是否是XStudent 例項: %i",[XStudent isMemberOfClass:[XStudent class]]);
// true (XStudent元類物件 = XStudent元類物件)
NSLog(@"XStudent是否是XStudent元類 例項: %i",[XStudent isMemberOfClass:object_getClass([XStudent class])]);
// false (XStudent元類物件 != XPerson元類物件)
NSLog(@"XStudent是否是XPerson元類 例項: %i",[XStudent isMemberOfClass:

 

isKindOfClass

- 呼叫者是傳入的類的例項物件,或者呼叫者是傳入類的繼承者鏈中的類的例項物件,則返回YES
- 判斷呼叫者是否是傳入物件的子類,別弄反了
- 不進行父類遞迴去查詢判斷

原始碼:

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->super_class) {
        if(tcls == cls) return YES;
    }
    return NO;
}
-(BOOL)isKindOfClass:(Class)cls {
    for(Class tcls = [self class]; tcls; tcls = tcls->super_class) {
        if(tcls == cls) return YES;
    }
    return NO;
}

 

例項程式碼:

XPerson* p1 = [[XPerson alloc]init];
XStudent* s1 = [[XStudent alloc]init];

// true (用s1的類物件、父類類物件、基類類物件([NSObject class]) 去和 p1的類物件比較,[p1 class]是s1的父類類物件)
NSLog(@"s1是否是p1 子類: %i",[s1 isKindOfClass:[p1 class]]);
// true (同上:[XPerson class] 與 [p1 class]是等同的)
NSLog(@"s1是否是XPerson 子類: %i",[s1 isKindOfClass:[XPerson class]]);
// true ([NSObject class]是s1的基類類物件)
NSLog(@"s1是否是NSObject 子類: %i",[s1 isKindOfClass:[NSObject class]]);

// false (用 XStudent的元類、父元類、基類(NSObject類物件) 去與 XPerson的物件比較)
NSLog(@"XStudent是否是XPerson 子類: %i",[XStudent isKindOfClass:[XPerson class]]);
// true (類方法需要傳入 元類進去判斷,裡面會取 XStudent 元類去比較)
NSLog(@"XStudent是否是XPerson元類 子類: %i",[XStudent isKindOfClass:object_getClass([XPerson class])]);
// true (元類的最上層就是基元類)
NSLog(@"XStudent是否是NSObject元類 子類: %i",[XStudent isKindOfClass:object_getClass([NSObject class])]);

 

相關文章