Update 2017
As GGregBrown noted in a comment, the original answer of 2013 does not work in 2017. I assume that the original answer really worked in 2013, since my practice is not to answer without testing, but I no longer have the code I used.
So how do you solve this in 2017? The easiest answer is swizzling, and some of them will find a contradiction, but it is not necessary to use blocks. Below is a quick proof of concept with the following reservations:
It is not thread safe. Think about what might happen if two or more threads execute code at the same time. Standard methods will solve this.
Efficiency has not been taken into account! For example, you can run swizzle dealloc once for each class and save the observer / key path list in the instance-related object.
This code only supports automatic deletion; you cannot manually delete an observer. You can change that.
The code:
@implementation AutoRemovedKVO typedef void (*DeallocImp)(id, SEL); + (void)forTarget:(NSObject *)target addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context {
Both uses of __unsafe_unretained are intended to eliminate the effects of ARC. In particular, methods usually retain their self argument, dealloc methods do not, and blocks follow the same persistence model as needed. To use a block as an implementation of dealloc , this behavior must be overridden, for which __unsafe_unretained used.
To use the code above, you simply replace:
[b addObserver:a forKeyPath:keyPath options:options context:NULL]
from:
[AutoRemovedKVO forTarget:b addObserver:a forKeyPath:keyPath options:options context:NULL]
Given the above warnings, the above code will do the job in 2017 (no warranty for future years!)
Original answer 2013
Here, in general terms, you can handle this and similar situations.
First find related objects. In short, you can attach related objects to any other object (using objc_setAssociatedObject ) and indicate that the related object should be kept as long as the object to which it is attached is around (using OBJC_ASSOCIATION_RETAIN ).
Using related objects, you can arrange for automatic removal of the observer when the observed object is released. Let X be an observer, and Y be observable objects.
Create an “unregistered” class, say Z, which accepts (via init) X and Y and in its dealloc method does removeObserver .
To set up surveillance, X:
- Creates an instance of Z, passing itself and Y.
- Registers itself as an observer Y.
- Associates Z with Y.
Now that Y is freed, Z will be freed, which will cause Z dealloc be called and unregister X.
If you need to remove the observation X while Y is still active, you do this by deleting the associated object - and this will result in its dealloc ...
You can use this template whenever you want to call something when another object is freed.
NTN