This experimental class allows you to say something like:
[someObject irPerformOnDeallocation: ^ { [[NSNotificationCenter defaultCenter] removeObserver:aNotificationCenterObject]; }];
This class was written because I wanted to provide a read-only NSManagedObjectContext that updates itself. This allows the single context to be shared among many view controllers. As long as none of the view controllers modify anything, this will be harmless, since it’s equivalent to sharing a read-only managed object context. Compared to having every single one of them create a managed object context, listen for save notifications, and handle merging (often repeatedly and on a massive number) this is obviously a better solution when you have many views from many view controllers together on one screen. Change tracking can be hooked up thru object graph KVO, or NSFetchedResultsController delegation, instead of explicit object refreshing.
The auto-updated context is emitted by IRDataStore, and it’ll listen for NSManagedObjectContextDidSaveNotification. The gotcha is we’ll have to de-register the opaque object returned by the notification center as soon as the context is deallocated. Since the context might have many users, it must handle this on its own; otherwise, encapsulation is broken — there is simply no other logical place to do this, nevertheless. It is not okay for the end objects using the context to manage notification center de-registration. So, the context should do the registration / de-registration on its own. (The auto-updating context must outlive its users, though the users simply need to retain the context, which is obvious.)
Under the hood, we want -[NSObject dealloc] notifications that work for any arbitrary Objective-C class, but won’t run unless explicitly specified; it also needs to be extremely performant. So, enter associated references… Associated references in Objective-C is a way to associate any arbitrary object pointer onto any other arbitrary Objective-C object, and it does memory management for you if correctly asked.
The gotcha is that associated references, even though associated using OBJC_ASSOCIATION_RETAIN and so, will not be released correctly when the host object is deallocated. So, we need a way to dynamically inject code into the host object’s -dealloc that calls objc_removeAssociatedObjects() provided that the user is well educated of its consequences:
In general, however, you are discouraged from using this function because it breaks all associations for all clients. Use this function only if you need to restore an object to “pristine condition.”.
Enter -[NSObject irPerformOnDeallocation:], which will attempt to dynamically create a subclass of the receiver’s own class, which has an overridden -dealloc. The overridden IMP would call objc_removeAssociatedObjects(self). We can simply, then, make as many IRLifetimeHelper objects, containing blocks that get called on -[IRLifetimeHelper dealloc], and put them in a mutable set associated with the host object. Once the mutable set goes, everything goes, and the blocks will be run.
Thanks to Dave DeLong for inspiration.
Code written while straightening hair.
Update: objc_removeAssociatedObjects() is automatically called on object deallocation already, it was simply not working immediately for me because the mutable set could be autoreleased; there is no need to dynamically subclass anything at all. Plus the original dynamic subclassing code breaks horribly on hidden class clusters (on objects reporting an potentially inaccurate [self class] such as NSString).