2011-09-28 51 views
1

我需要檢查一個對象是否是NSNotification。僅僅知道它是否是一個子類是不夠的,因爲我想區分它是NSNotification還是NSNotification的子類。NSNotification的測試類型

所以來闡述我需要以下區分:

  1. 的NSConcreteNotification
  2. NSNotification的一個子類(但不是NSConcreteNotification)

的問題是,NSNotifications實際上NSConcreteNotifications和NSConcreteNotification是一個私人類,所以我不能用它來測試。

[object isMemberOfClass: [NSNotification class]] // returns NO in both cases 
[object isKindOfClass: [NSNotification class]] // returns YES in both cases 
+0

您測試的對象是NSNotification no的子類? – Geoffroy

+0

您可以使用objective-C的isMemberOfClass方法。請參閱[isMemberOfClass] [1] [1]:http://stackoverflow.com/questions/2045561/objective-c-iskindofclass-missunderstanding – Naved

+0

的對象可以是1,一種NSConcreteNotification或2。 NSNotification的子類。我需要分辨差異。 – Undistraction

回答

2

沒有理由按照您描述的方式子分類NSNotification。首先,NSNotification已經攜帶一個userInfo字典。你可以把你想要的任何數據放在那裏。如果你喜歡,我可以使用類別方法來讀取和寫入該字典(我一直這樣做)。例如,我想要做的事情是傳遞一些對象,比如RNMessage。所以,我創建了一個類別,看起來像這樣:

@interface NSNotificationCenter (RNMessage) 
- (void)postNotificationName:(NSString *)aName object:(id)anObject message:(RNMessage *)message; 
@end 

@interface NSNotification (RNMessage) 
- (RNMessage *)message; 
@end 

static NSString * const RNMessageKey = @"message"; 

@implementation NSNotificationCenter (RNMessage) 
- (void)postNotificationName:(NSString *)aName object:(id)anObject message:(RNMessage *)message { 
    [self postNotificationName:aName object:anObject userInfo:[NSDictionary dictionaryWithObject:message forKey:RNMessageKey]; 
} 
@end 

@implementation NSNotification (RNMessage) 
- (RNMessage *)message { 
    return [[self userInfo] objectForKey:RNMessageKey]; 
} 

由於@hypercrypt筆記,你也可以使用相關的引用附加數據的任意對象,而無需創建一個實例變量,但NSNotification它的使用userInfo字典要簡單得多。使用NSLog打印通知要容易得多。更容易序列化它們。更容易複製它們。等相關的參考文獻很好,但是他們確實增加了很多小角落案例,如果你能擺脫它,你應該避免。

+0

非常好。這真的很有幫助。非常感激。 – Undistraction

1

要測試ID對象是NSNotification使用:

[object isMemberOfClass:[NSNotification class]];` 

爲了測試是否是一個NSConcreteNotifications使用

[object isMemberOfClass:NSClassFromString(@"NSConcreteNotifications")]; 

改變字符串到不同類的名稱需要...

然後,您可以將兩個檢查合併爲'NSNotification的子類(但不是NSConcreteNotification)。

或者:

if ([object isMemberOfClass:NSClassFromString(@"NSConcreteNotifications")]) 
{ 
    // It's a NSConcreteNotifications... 
} 
else if ([object isKindOfClass:[NSNotification class]]) 
{ 
    // It's an NSNotification (or subclass) but not an NSConcreteNotifications 
} 

或者

if ([object isKindOfClass:[NSNotification class]] && ![object isMemberOfClass:NSClassFromString(@"NSConcreteNotifications")]) 
{ /* ... */ } 

如果你想將屬性添加到NSNotification是你應該看看Associative References

的基本思路是:

static const char objectKey; 
- (id)object 
{ 
    return objc_getAssociatedObject(self, &objectKey); 
} 

- (void)setObject:(id)object 
{ 
    objc_setAssociatedObject(self, &objectKey, object, OBJC_ASSOCIATION_RETAIN); 
} 
+0

感謝您的回覆。但使用字符串似乎是一種非常不安全的方式。看起來奇怪的是,我們不得不採取硬編碼一個字符串來完成這樣一個簡單的任務。 – Undistraction

+0

爲什麼你需要區分兩者? – hypercrypt

+0

我將通知映射到命令,我希望這個選項是強類型。依靠一個字符串(通知的名稱)在我看來是一個糟糕的方式。 – Undistraction

1

這聽起來像一個非常糟糕的主意。當您第一次收到通知時,您已經知道它是什麼類型,因爲它作爲通知回調方法的顯式參數傳遞。考慮將通知存儲爲另一個對象的強類型屬性,或者如果您將其添加到集合中,則將其插入字典下的字典中,或者將其傳遞給其他方法,而這些方法不保留類型信息以使其更容易以後再確定。

創建私有API的依賴關係(包括私有類的名稱)會使您的代碼更脆弱,並且更有可能在未來的發行版中崩潰。顯然,這些課程是私密的原因之一是讓蘋果的工程師更容易地改變它們,因爲他們認爲合適。例如,在最近的SDK版本中,NSArray和NSMutableArray使用的具體子類剛剛發生了變化。

+0

我完全理解這是一個壞主意,這就是爲什麼我試圖找到一個替代。我想使用具有自定義屬性的通知,這意味着我別無選擇,只能將NSNotification子類化,蘋果在其文檔中稱其爲NSNotification。我的部分要求是,當我收到通知時,我可以檢查它是否是NSNotification或NSNotification的子類,以便我可以採取適當的行動。 – Undistraction

+1

您可以添加屬性,而無需使用關聯對象的類別進行子類化... – hypercrypt

+0

我的印象是,無法在類別中合併屬性? – Undistraction

1

正如其他人指出的那樣,依靠私人班的名字是一個壞主意。如果你正在尋找一個特定的子類,你可以明確地檢查那個類。

[notification isMemberOfClass:[MyNotificationSubclass class]]; 

您可以使用多個語句來檢查多個子類,但這會有點混亂。每次添加新類以查找時,此方法也需要更改。定義一個只讀屬性可能會更好,該屬性指示通知是否支持您正在尋找的功能,所以您不會像班級的能力那樣依賴於班級。您可以在NSNotification上使用一個類別,該類別僅爲此屬性返回NO,並且具有此功能的任何子類都將覆蓋返回YES的方法。

@interface NSNotification (MyFeature) 
@property (readonly) BOOL hasMyFeature; 
@end 

@implementation NSNotification (MyFeature) 
- (BOOL)hasMyFeature { 
    return NO; 
} 
@end 

在支持它的子類:

- (BOOL)hasMyFeature { 
    return YES; 
} 
- (void)performMyFeature { 
    ... 
} 

這也將允許您更改通知是否具有改變其返回hasMyFeature標誌啓用此功能,和你的支票代碼將簡單地爲:

if(notification.hasMyFeature) [notification performMyFeature]; 
+0

更慣用的(實現時間越短,使用時間越長)可能是'if([notification respondsToSelector:@selector(performMyFeature)])[notification performMyFeature];'然後你不再需要'hasMyFeature'屬性。 – Quuxplusone

+0

@Quuxplusone正確。現在想想看,你也可以添加一個空的'performMyFeature'方法,那麼你根本就不需要檢查。但我會保持原樣,因爲在很多情況下我更喜歡這種風格。 – ughoavgfhw