2011-09-28 50 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