objective-ccocoainheritancensnotificationclass-cluster

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


I am trying to subclass NSNotification.

Apple's docs for NSNotificationstate the following:

NSNotification is a class cluster with no instance variables. As such, you must subclass NSNotification and override the primitive methods name, object, and userInfo. You can choose any designated initializer you like, but be sure that your initializer does not call NSNotification’s implementation of init (via [super init]). NSNotification is not meant to be instantiated directly, and its init method raises an exception.

But this isn't clear to me. Should I create an initializer like this?

-(id)initWithObject:(id)object
{
    return self;
}

Solution

  • 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);
    }
    
    ...