Search code examples
iosobjective-cnsnotificationcenternsnotificationsobjective-c-category

Observe and remove an NSNotification within a category before dealloc


I am currently observing a notification throughout the life of an object in a category. However, I am swizzling the dealloc method to have a spot to remove the observation. This feels bad and I am uncomfortable with it, additionally I am running into problems.

Does anyone have any ideas how I can stop observing the notification just before the object will be deallocated within a category?


Solution

  • The best way to run code at the deallocation of an object for which you can't override dealloc is by using associated objects.

    The object that you associate to will release its strongly-held associated objects when it deallocates. As long as that is the only owner, the associated object's dealloc will then be called. Using a class you control for the associated object, that's your entry point.

    I've got a demonstration of using this trick to deregister for KVO in a GitHub repo https://github.com/woolsweater/UIViewController-WSSDataBindings

    The controller associates a helper object to itself:

    - (void)WSSBind:(NSString *)bindingName
       toObject:(id)target
    withKeyPath:(NSString *)path
    {
        WSSBinding * binding = [WSSBinding bindingWithBoundName:bindingName
                                                       onObject:self
                                                      toKeyPath:path
                                                       ofObject:target];
    
        // Attach the binding to both target and controller, but only make it
        // owned by the target. This provides automatic deregistration when the
        // target is destroyed, and allows the controller to unbind at will.
        // Disregard the target and bound path for the key to allow mirroring
        // Cocoa's unbind: method; this is simplest for the controller.
        NSUInteger key = [self WSSAssociateKeyForBinding:bindingName];
        objc_setAssociatedObject(target, (void *)key, binding,
                                 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        objc_setAssociatedObject(self, (void *)key, binding,
                                 OBJC_ASSOCIATION_ASSIGN);
    }
    

    And the WSSBinding class implements dealloc to remove the observer that's been set up elsewhere. You can do the same for your NSNotification registration.