2012-06-08 42 views
27

我在理解蘋果指南中定義的「Testing Class Equality」這部分的問題。Objective-c中的「Testing Class Equality」

在動態創建的子類中,通常會覆蓋類方法,以致子類僞裝成它所替代的類。在測試類相等性時,應該比較類方法返回的值而不是較低級函數返回的值。在API方面的投入,以下不等式屬於動態子類:

[object class] != object_getClass(object) != *((Class*)object) 

因此,應該測試兩個班的平等如下:

if ([objectA class] == [objectB class]) { //... 
+6

或isMemberOfClass - http://stackoverflow.com/questions/383978/how-useful-is-the-nsobject-ismemberofclass-method – 9dan

+1

你在這裏的目標是什麼?你正在測試一個對象的類,或比較兩個對象的類,或...?當然'*((Class *)對象)'不會等於獲得類對象的任何一個過程的結果 - 你不能只將一個實例轉換爲一個類(同樣,'Class'類型已經一個指針)。 –

+0

對不起,我忘了提到它從蘋果指南,我沒有得到這整個測試類平等的事情......這整個段是從蘋果指導... –

回答

40

有些情況下人們在運行時添加新類。 Key Value Observing就是一個例子:當你觀察一個對象時,Foundation框架會創建一個觀察對象類的新子類。這個動態類的行爲與其超類相同,但將KVO通知添加到所有的增變器方法。

您引用的段落說Objective-C運行時可以告訴這個新類與原始類不同。但是,因爲它只是KVO構建方式的實現細節,所以您不應該知道或關心它。因此,開發人員推翻了他們新類的-class方法,假裝對象仍然是原始類的成員。

如果您想檢查兩個對象是否具有相同的類,那麼您必須將它們的-class方法(將KVO等技巧考慮在內)的結果進行比較,而不是使用運行時函數。

下面是一個例子:

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     NSObject *observer = [NSObject new]; 
     NSObject *model = [NSObject new]; 

     [model addObserver: observer forKeyPath: @"count" options: 0 context: NULL]; 

     //using -class methods: 
     NSLog(@"model is a %@, observer is a %@", [model class], [observer class]); 

     //casting to Class: 
     NSLog(@"model is a %@, observer is a %@", *(Class*)model, *(Class*)observer); 

     //using the runtime: 
     NSLog(@"model is a %@, observer is a %@", object_getClass(model), object_getClass(observer)); 

     [model removeObserver: observer forKeyPath: @"count" context: NULL]; 
     [model release]; 
     [observer release]; 
    } 
    return 0; 
} 

你看到我做的是創建兩個對象,告訴他們一個觀察對方,然後找出什麼他們的類。下面是結果:

2012-06-08 08:37:26.904無題2 [896:707]模型是一個NSObject的, 觀察者是NSObject的

2012-06-08 8點37 :26.907無題2 [896:707] 模型是一個NSKVONotifying_NSObject,觀察者是NSObject的

2012-06-08 08:37:26.907無題2 [896:707]模型是一個NSKVONotifying_NSObject, 觀察者是一個NSObject

正如文檔所示,這只是第一種情況(我們在此比較-class),它可以完成應用程序代碼可以合理預期的任何操作。另外兩種查找類的方法 - 詢問運行時,並將對象指針投射到Class * - 都提供了關於KVO如何將我們下層的類改變的實現細節,並且表示類比較現在不會顯示班級是平等的。

因爲其他的答案和評論都提到-isMemberOfClass:-isKindOfClass:,我將介紹這些點太:

  • -isKindOfClass:類平等的測試。 [object isKindOfClass: aClass]如果objectaClass或其任何小類的實例,則爲真。因爲你引用的段落是關於課堂平等的,-isKindOfClass:在這裏並不相關。也就是說,這通常是您想要在應用程序代碼中進行的測試。關心「我可以使用這個對象作爲Foo?」的答案更爲常見。比「這個對象是否完全是Foo?」。

  • -isMemberOfClass:是對等級相等的測試:[object isMemberOfClass: aClass]只有在對象是aClass的實例時才爲真。該測試使用-class方法的結果完成,這意味着在該示例中model[model isMemberOfClass: [NSObject class]]測試爲肯定的。

+0

'*(Class *)model'優先於'*(model-> isa)'嗎? –

+1

兩者都不是首選,因爲兩者都依靠以'-class'不打破的方式打破封裝。 – 2012-06-12 20:25:48

5

它應該是:

if([objctA isKindOfClass [MyClass class]]) 
+6

這是一個不同的測試。 'isKindOfClass:'不測試類的相等性,它測試被測試的對象是指定類的成員_或任何子類_。 – 2012-06-08 07:30:20

1

也許你可以使用'NSStringFromClass'方法並比較得到的字符串感謝'isEqualToString'?