簡體   English   中英

NSNotification的測試類型

[英]Test type of 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

沒有理由按照您描述的方式對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所述,您還可以使用關聯的引用將數據附加到任意對象,而無需創建ivar,但是使用NSNotification ,使用userInfo字典要簡單得多。 使用NSLog打印通知要容易得多。 易於序列化。 更容易復制它們。 等等,關聯的引用很好,但是它們確實增加了很多小問題,如果可以避免的話,應該避免使用。

要測試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添加屬性,則應查看“ 關聯引用”

基本思想是:

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

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

這聽起來像是一個非常糟糕的主意。 第一次收到通知時,您已經知道它的類型,因為它已作為顯式參數傳遞給通知回調方法。 考慮將通知存儲為另一個對象的強類型屬性,或者將通知添加到集合中,或者在適當的鍵下插入字典中,或者將其傳遞給不保留類型信息的其他方法,以簡化通知以便以后識別。

在私有API(包括私有類的名稱)上創建依賴關系將使您的代碼更加脆弱,並且在將來的發行版中更有可能被破壞。 顯然,這些類是私有的原因之一是使Apple的工程師更容易根據需要更改它們。 例如,NSArray和NSMutableArray使用的具體子類在最新版的SDK中已更改。

正如其他人指出的那樣,依靠私有類的名稱是一個壞主意。 如果要查找一個特定的子類,則可以顯式檢查該類。

[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];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM