123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- //
- // RACKVOTrampoline.m
- // ReactiveObjC
- //
- // Created by Josh Abernathy on 1/15/13.
- // Copyright (c) 2013 GitHub, Inc. All rights reserved.
- //
- #import "RACKVOTrampoline.h"
- #import "NSObject+RACDeallocating.h"
- #import "RACCompoundDisposable.h"
- #import "RACKVOProxy.h"
- @interface RACKVOTrampoline ()
- // The keypath which the trampoline is observing.
- @property (nonatomic, readonly, copy) NSString *keyPath;
- // These properties should only be manipulated while synchronized on the
- // receiver.
- @property (nonatomic, readonly, copy) RACKVOBlock block;
- @property (nonatomic, readonly, unsafe_unretained) NSObject *unsafeTarget;
- @property (nonatomic, readonly, weak) NSObject *weakTarget;
- @property (nonatomic, readonly, weak) NSObject *observer;
- @end
- @implementation RACKVOTrampoline
- #pragma mark Lifecycle
- - (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
- NSCParameterAssert(keyPath != nil);
- NSCParameterAssert(block != nil);
- NSObject *strongTarget = target;
- if (strongTarget == nil) return nil;
- self = [super init];
- _keyPath = [keyPath copy];
- _block = [block copy];
- _weakTarget = target;
- _unsafeTarget = strongTarget;
- _observer = observer;
- [RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
- [strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
- [strongTarget.rac_deallocDisposable addDisposable:self];
- [self.observer.rac_deallocDisposable addDisposable:self];
- return self;
- }
- - (void)dealloc {
- [self dispose];
- }
- #pragma mark Observation
- - (void)dispose {
- NSObject *target;
- NSObject *observer;
- @synchronized (self) {
- _block = nil;
- // The target should still exist at this point, because we still need to
- // tear down its KVO observation. Therefore, we can use the unsafe
- // reference (and need to, because the weak one will have been zeroed by
- // now).
- target = self.unsafeTarget;
- observer = self.observer;
- _unsafeTarget = nil;
- _observer = nil;
- }
- [target.rac_deallocDisposable removeDisposable:self];
- [observer.rac_deallocDisposable removeDisposable:self];
- [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
- [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- if (context != (__bridge void *)self) {
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- return;
- }
- RACKVOBlock block;
- id observer;
- id target;
- @synchronized (self) {
- block = self.block;
- observer = self.observer;
- target = self.weakTarget;
- }
- if (block == nil || target == nil) return;
- block(target, observer, change);
- }
- @end
|