RACKVOTrampoline.m 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. //
  2. // RACKVOTrampoline.m
  3. // ReactiveObjC
  4. //
  5. // Created by Josh Abernathy on 1/15/13.
  6. // Copyright (c) 2013 GitHub, Inc. All rights reserved.
  7. //
  8. #import "RACKVOTrampoline.h"
  9. #import "NSObject+RACDeallocating.h"
  10. #import "RACCompoundDisposable.h"
  11. #import "RACKVOProxy.h"
  12. @interface RACKVOTrampoline ()
  13. // The keypath which the trampoline is observing.
  14. @property (nonatomic, readonly, copy) NSString *keyPath;
  15. // These properties should only be manipulated while synchronized on the
  16. // receiver.
  17. @property (nonatomic, readonly, copy) RACKVOBlock block;
  18. @property (nonatomic, readonly, unsafe_unretained) NSObject *unsafeTarget;
  19. @property (nonatomic, readonly, weak) NSObject *weakTarget;
  20. @property (nonatomic, readonly, weak) NSObject *observer;
  21. @end
  22. @implementation RACKVOTrampoline
  23. #pragma mark Lifecycle
  24. - (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
  25. NSCParameterAssert(keyPath != nil);
  26. NSCParameterAssert(block != nil);
  27. NSObject *strongTarget = target;
  28. if (strongTarget == nil) return nil;
  29. self = [super init];
  30. _keyPath = [keyPath copy];
  31. _block = [block copy];
  32. _weakTarget = target;
  33. _unsafeTarget = strongTarget;
  34. _observer = observer;
  35. [RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
  36. [strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
  37. [strongTarget.rac_deallocDisposable addDisposable:self];
  38. [self.observer.rac_deallocDisposable addDisposable:self];
  39. return self;
  40. }
  41. - (void)dealloc {
  42. [self dispose];
  43. }
  44. #pragma mark Observation
  45. - (void)dispose {
  46. NSObject *target;
  47. NSObject *observer;
  48. @synchronized (self) {
  49. _block = nil;
  50. // The target should still exist at this point, because we still need to
  51. // tear down its KVO observation. Therefore, we can use the unsafe
  52. // reference (and need to, because the weak one will have been zeroed by
  53. // now).
  54. target = self.unsafeTarget;
  55. observer = self.observer;
  56. _unsafeTarget = nil;
  57. _observer = nil;
  58. }
  59. [target.rac_deallocDisposable removeDisposable:self];
  60. [observer.rac_deallocDisposable removeDisposable:self];
  61. [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
  62. [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
  63. }
  64. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
  65. if (context != (__bridge void *)self) {
  66. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  67. return;
  68. }
  69. RACKVOBlock block;
  70. id observer;
  71. id target;
  72. @synchronized (self) {
  73. block = self.block;
  74. observer = self.observer;
  75. target = self.weakTarget;
  76. }
  77. if (block == nil || target == nil) return;
  78. block(target, observer, change);
  79. }
  80. @end