Last active
August 29, 2015 14:06
-
-
Save fjolnir/eb95e20a4fb7af2f1c32 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <objc/runtime.h> | |
#import <objc/message.h> | |
@interface NSObject (KVOAutoRemoval) | |
- (void)cy_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; | |
@end | |
@interface _CYDeallocHandler : NSObject | |
@property(nonatomic, copy) void (^block)(); | |
@end | |
@implementation _CYDeallocHandler | |
- (void)dealloc { _block(); } | |
@end | |
@implementation NSObject (KVOAutoRemoval) | |
- (void)cy_addObserver:(NSObject *)aObserver forKeyPath:(NSString *)aKeyPath options:(NSKeyValueObservingOptions)aOptions context:(void *)aContext | |
{ | |
[self addObserver:aObserver forKeyPath:aKeyPath options:aOptions context:aContext]; | |
__block void *selfPtr = (__bridge void *)self; | |
__unsafe_unretained id unsafeObserver = aObserver; | |
void (^block)() = ^{ | |
void * const observed = selfPtr; | |
if(observed && OSAtomicCompareAndSwapPtr(observed, nil, &selfPtr)) | |
[(__bridge id)observed removeObserver:unsafeObserver forKeyPath:aKeyPath context:aContext]; | |
}; | |
_CYDeallocHandler *handlerA = [_CYDeallocHandler new]; | |
_CYDeallocHandler *handlerB = [_CYDeallocHandler new]; | |
handlerA.block = block; | |
handlerB.block = block; | |
objc_setAssociatedObject(self, | |
(void *)((uintptr_t)(__bridge void *)aObserver ^ (uintptr_t)(__bridge void *)aKeyPath ^ (uintptr_t)aContext), | |
handlerA, OBJC_ASSOCIATION_RETAIN); | |
objc_setAssociatedObject(aObserver, | |
(void *)((uintptr_t)(__bridge void *)self ^ (uintptr_t)(__bridge void *)aKeyPath ^ (uintptr_t)aContext), | |
handlerB, OBJC_ASSOCIATION_RETAIN); | |
} | |
@end | |
// -------------------------- | |
@interface Foo : NSObject | |
@property NSString *test; | |
@end | |
@implementation Foo | |
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context | |
{ | |
NSLog(@">>> %@ %@ -> %@", keyPath, object, [object valueForKeyPath:keyPath]); | |
} | |
@end | |
int main(int argc, char *argv[]) { | |
@autoreleasepool { | |
Foo *a = [Foo new]; | |
Foo *b = [Foo new]; | |
[a cy_addObserver:b forKeyPath:@"test" options:0 context:NULL]; | |
a.test = @"asdf"; | |
b = nil; | |
a.test = @"foo"; | |
a = nil; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment