Is subclassing NSNotification the right route if I want to add typed properties? Is subclassing NSNotification the right route if I want to add typed properties? objective-c objective-c

Is subclassing NSNotification the right route if I want to add typed properties?


Subclassing NSNotification is an atypical operation. I think I've only seen it done once or twice in the past few years.

If you're looking to pass things along with the notification, that's what the userInfo property is for. If you don't like accessing things through the userInfo directly, you could use a category to simplify access:

@interface NSNotification (EasyAccess)@property (nonatomic, readonly) NSString *foo;@property (nonatomic, readonly) NSNumber *bar;@end@implementation NSNotification (EasyAccess)- (NSString *)foo {  return [[self userInfo] objectForKey:@"foo"];}- (NSNumber *)bar {  return [[self userInfo] objectForKey:@"bar"];}@end

You can also use this approach to simplify NSNotification creation. For example, your category could also include:

+ (id)myNotificationWithFoo:(NSString *)foo bar:(NSString *)bar object:(id)object {  NSDictionary *d = [NSDictionary dictionaryWithObjectsForKeys:foo, @"foo", bar, @"bar", nil];  return [self notificationWithName:@"MyNotification" object:object userInfo:d];}

If, for some strange reason, you'd need the properties to be mutable, then you'd need to use associative references to accomplish that:

#import <objc/runtime.h>static const char FooKey;static const char BarKey;...- (NSString *)foo {  return (NSString *)objc_getAssociatedObject(self, &FooKey);}- (void)setFoo:(NSString *)foo {  objc_setAssociatedObject(self, &FooKey, foo, OBJC_ASSOCIATION_RETAIN);}- (NSNumber *)bar {  return (NSNumber *)objc_getAssociatedObject(self, &BarKey);}- (void)setBar:(NSNumber *)bar {  objc_setAssociatedObject(self, &BarKey, bar, OBJC_ASSOCIATION_RETAIN);}...


It seems this does work. For example:

#import "TestNotification.h"NSString *const TEST_NOTIFICATION_NAME = @"TestNotification";@implementation TestNotification-(id)initWithObject:(id)object{    object_ = object;    return self;}-(NSString *)name{    return TEST_NOTIFICATION_NAME;}-(id)object{    return object_;}- (NSDictionary *)userInfo{    return nil;}@end

also beware a massive Gotcha related to NSNotifications. The type of NSNotifications greated using NSNotification notificationWithName:object: is NSConcreteNotification, not NSNotification. And to make it a little more awkward, if you are checking for class, NSConcreteNotification is private so you have nothing to compare to.


You don’t set it, exactly—you just override the implementation of the name method so it returns what you want. In other words:

- (NSString *)name{    return @"Something";}

Your initializer looks fine—I haven’t seen an example of an init that doesn’t call its superclass’s implementation before, but if that’s what the doc’s saying you should do, it’s probably worth a try.