一、isKindOfClass、isMemberOfClass 作用分別是什么
isKindOfClass方法的作用是判斷一個對象是否為指定類或指定類的子類的實例。如果是,返回YES;否則,返回NO。該方法會遞歸地向上檢查對象所屬的父類,直到父類為根類NSObject(或派生自NSObject的類)為止。isMemberOfClass方法的作用是判斷一個對象是否為指定類的實例。如果是,返回YES;否則,返回NO。
isKindOfClass:
類方法:元類 –> 根元類 –> 根類 –> nil 與 傳入類的對比實例方法:對象的類 –> 父類 –> 根類 –> nil 與 傳入類的對比isMemberOfClass:
類方法:?類的元類與傳入類對比實例方法:對象的父類與傳入類對比不同的指向:
isa的指向:對象的 isa 指向類; 類的 isa 指向元類;元類的 isa 指向根元類;根元類的 isa 指向自己。類的superclass的指向:類的 superclass 指向父類, 父類的 superclass 指向根類 ,根類的superclass 指向nil。元類的superclass的指向:元類的 superclass 指向父類的元類,父元類的 superclass 指向根類的元類根元類的 superclass 指向根類,根類的 superclass 指向 nil。和isKindOfClass不同的是,isMemberOfClass只會檢查對象的實際類型是否與指定類相同,不會向上檢查其父類。
二、isKindOfClass和isMemberOfClass的區別
首先看看兩個方法的蘋果官方解釋:
isKindOfClass:Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class. (required)
這個方法用來判斷一個對象是否是指定類或者某個從該類繼承類的實例對象。
isMemberOfClass:Returns a Boolean value that indicates whether the receiver is an instance of a given class. (required)
這個方法用來判斷一個對象是否是指定類的實例對象。
兩者區別:
isKindOfClass 可以判斷某對象是否是某個類的實例對象,這個類和這個類的繼承類都可以判斷;isMemberOfClass只能判斷對象是否是當前類的實例對象。isMemberOfClass和isKindOfClass的應用舉例:
UIScrollView *scrollView = [[UIScrollView alloc] init];if ([scrollView isKindOfClass:[UIView class]]) { NSLog(@"scrollView is isKindOfClass UIView");}if ([scrollView isKindOfClass:[UIScrollView class]]) { NSLog(@"scrollView is isKindOfClass UIScrollView");}if ([scrollView isMemberOfClass:[UIView class]]) { NSLog(@"scrollView is isMemberOfClass UIView");}if ([scrollView isMemberOfClass:[UIScrollView class]]) { NSLog(@"scrollView isMemberOfClass UIScrollView");}
輸出結果:
scrollView is isKindOfClass UIView
scrollView is isKindOfClass UIScrollView
scrollView isMemberOfClass UIScrollView
另外需要特別注意的是NSArray、NSMutableArray這樣的類,蘋果官方文檔有這樣一段描述:
在類集群表示的對象上使用此方法時要小心。由于類集群的性質,您返回的對象可能并不總是您所期望的類型。如果您調用返回類集群的方法,則該方法返回的確切類型是您可以對該對象執行的操作的優異指示器。例如,如果一個方法返回一個指向NSArray對象的指針,你不應該使用這個方法來查看數組是否可變,如下面的代碼所示:
// DO NOT DO THIS!if ([myArray isKindOfClass:[NSMutableArray class]]){ // Modify the object}
如果您在代碼中使用這樣的結構,您可能會認為修改實際上不應該修改的對象是可以的。這樣做可能會給其他希望對象保持不變的代碼帶來問題。如果接收對象是一個類對象,如果aClass是相同類型的class對象,此方法返回YES,否則返回NO。
測試結果:
NSArray *testArray = [[NSArray alloc] init];NSMutableArray *testArray2 = [[NSMutableArray alloc] init];if ([testArray isKindOfClass:[NSArray class]]) { NSLog(@"testArray isKindOfClass of NSArray");}if ([testArray isMemberOfClass:[NSArray class]]) { NSLog(@"testArray isMemberOfClass of NSArray");}if ([testArray2 isKindOfClass:[NSMutableArray class]]) { NSLog(@"testArray2 isKindOfClass of NSMutableArray");}if ([testArray2 isMemberOfClass:[NSMutableArray class]]) { NSLog(@"testArray2 isMemberOfClass of NSMutableArray");}
控制臺輸出:
testArray isKindOfClass of NSArray
testArray2 isKindOfClass of NSMutableArray
各種查詢得出的結論是:NSArray、NSMutableArray屬于類簇,使用isMemberOfClass不能取到正確的結果。原因是:由于類簇的性質,這類對象實際返回的實例有不確定性。NSArray對象可能會在運行時發現其實運作的是NSCFArray(來自Core Foundation框架(C語言的實現版本),很多Cocoa對象都是如此做橋接的)。總之對于類簇的判斷要謹慎。
延伸閱讀1:isKindOfClass、isMemberOfClass的用法
不管是isKindOfClass還是isMemberOfClass,在類對象調用時,都是與調用者的元類對象與傳入參數進行判斷,在實例對象調用時,不管是isKindOfClass還是isMemberOfClass,都是與調用者的類對象與傳入參數進行判斷。isKindOfClass具有繼承關系,會沿著superclass遍歷;isMemberOfClass,則沒有繼承關系,只會判斷一次。