iOS中的 isKindOfClass 和 isMemberOfClass
先來看一個爛大街的面試題:
下面程式碼結果如何?
BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[TestObject class] isKindOfClass:[TestObject class]];
BOOL res4 = [(id)[TestObject class] isMemberOfClass:[TestObject class]];
答案:除了第一個是YES,其他三個都是NO。
在推測結果之前,首先要明白兩個問題。isKindOfClass
和 isMemberOfClass
的區別是什麼?
isKindOfClass:
returns YES if the receiver is an instance of the specified class or an instance of any class that inherits from the specified class.
方法呼叫者是傳入的類的例項物件,或者呼叫者是傳入類的繼承者鏈中的類的例項物件,則返回YES。
isMemberOfClass:
returns YES if the receiver is an instance of the specified class.
方法呼叫者必須是傳入的類的例項物件才返回YES。
我們從Runtime原始碼的角度來分析一下結果。
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (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;
}
平時開發過程中只會接觸到物件方法的isKindOfClass
和isMemberOfClass
,但是在NSObject
類中還隱式的實現了類方法版本。不只這兩個方法,其他NSObject
中的物件方法,都有其對應的類方法版本。因為在OC中,類和元類也都是物件。這四個呼叫由於都是類物件發起呼叫的,所以最終執行的都是類方法版本。
先把Runtime的物件模型拿出來,方便後面的分析。
因為呼叫類的class
方法,會把類自身直接返回,所以第一次呼叫者是NSObject
類物件,+ (BOOL)isKindOfClass:(Class)cls
方法的引數cls
也是NSObject
類物件。
進入到for
迴圈中,在此說明一下object_getClass()
方法相當於取出isa
指標指向的類,所以會從NSObject
的元類開始遍歷,所以第一次NSObject meta class != NSObject class
,匹配失敗。第二次迴圈將tcls
設定為superclass
的NSObject class
,NSObject class==NSObject class
,匹配成功。
NSObject
能匹配成功,是因為這個類比較特殊,在第二次獲取 superClass
的時候,NSObject
元類的superClass
就是NSObject
的類物件,所以會匹配成功。而其他三種匹配,則都會失敗,各位同學可以去自己分析一下剩下三種。
參考資料
相關文章
- iOS isKindOfClass與isMemberOfClass的區別iOS
- isKindOfClass和isMemberOfClass的區別
- isMemberOfClass、isKindOfClass原理分析
- iOS中的isEqual和hashiOS
- iOS 中 UIView 和 CALayer 的關係iOSUIView
- 聊聊iOS中的多繼承和多重代理iOS繼承
- iOS中的PromiseiOSPromise
- iOS中的StringiOS
- iOS 中 cell的用法iOS
- iOS中的動態庫,靜態庫和framework介紹iOSFramework
- [譯] Story 中 Type Mode 在 iOS 和 Android 上的實現iOSAndroid
- iOS 中的事件傳遞和響應機制 - 原理篇iOS事件
- iOS 中的事件傳遞和響應機制 - 實踐篇iOS事件
- iOS 中的事件傳遞和響應機制 – 實踐篇iOS事件
- APP測試中IOS和Android的區別,有哪些注意點?APPiOSAndroid
- 聊聊iOS中的動畫iOS動畫
- iOS tableView中的MVC、MVVMiOSViewMVCMVVM
- 關於 iOS 中的庫iOS
- iOS strong和copy的區別iOS
- ios instancetype和id的區別iOS
- [譯] iOS 裡的 MVVM 和 RxSwiftiOSMVVMSwift
- 玩轉iOS開發:iOS中的NSOperation開發(一)iOS
- iOS-Swift中的遞增(++)和遞減(--)被取消的原因-官方答覆iOSSwift
- iOS NSString中實用的方法iOS
- ios中的多播委託iOS
- iOS中的Reference Counting詳解iOS
- iOS中的螢幕導航iOS
- Protocol Buffers 在 iOS 中的使用ProtocoliOS
- iOS中優雅的使用iconfontiOS
- Appium 的 ios 中 webview 問題APPiOSWebView
- iOS中atomic和nonatomic區別及內部實現iOS
- iOS中的圖片使用方式、記憶體對比和最佳實踐iOS記憶體
- 解決 flutter module 中 .android 和 .ios 目錄不被覆蓋的問題FlutterAndroidiOS
- 『ios』view和tableview的截圖和圖片拼接iOSView
- iOS 中的 block 是如何持有物件的iOSBloC物件
- iOS 12 中的 Siri Shortcuts 簡介iOS
- iOS 中的 GCD 實現詳解iOSGC
- iOS開發中的幾種鎖iOS