RACDisposable.m 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. //
  2. // RACDisposable.m
  3. // ReactiveCocoa
  4. //
  5. // Created by Josh Abernathy on 3/16/12.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import "RACDisposable.h"
  9. #import "RACScopedDisposable.h"
  10. #import <libkern/OSAtomic.h>
  11. @interface RACDisposable () {
  12. // A copied block of type void (^)(void) containing the logic for disposal,
  13. // a pointer to `self` if no logic should be performed upon disposal, or
  14. // NULL if the receiver is already disposed.
  15. //
  16. // This should only be used atomically.
  17. void * volatile _disposeBlock;
  18. }
  19. @end
  20. @implementation RACDisposable
  21. #pragma mark Properties
  22. - (BOOL)isDisposed {
  23. return _disposeBlock == NULL;
  24. }
  25. #pragma mark Lifecycle
  26. - (id)init {
  27. self = [super init];
  28. if (self == nil) return nil;
  29. _disposeBlock = (__bridge void *)self;
  30. OSMemoryBarrier();
  31. return self;
  32. }
  33. - (id)initWithBlock:(void (^)(void))block {
  34. NSCParameterAssert(block != nil);
  35. self = [super init];
  36. if (self == nil) return nil;
  37. _disposeBlock = (void *)CFBridgingRetain([block copy]);
  38. OSMemoryBarrier();
  39. return self;
  40. }
  41. + (instancetype)disposableWithBlock:(void (^)(void))block {
  42. return [[self alloc] initWithBlock:block];
  43. }
  44. - (void)dealloc {
  45. if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;
  46. CFRelease(_disposeBlock);
  47. _disposeBlock = NULL;
  48. }
  49. #pragma mark Disposal
  50. - (void)dispose {
  51. void (^disposeBlock)(void) = NULL;
  52. while (YES) {
  53. void *blockPtr = _disposeBlock;
  54. if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
  55. if (blockPtr != (__bridge void *)self) {
  56. disposeBlock = CFBridgingRelease(blockPtr);
  57. }
  58. break;
  59. }
  60. }
  61. if (disposeBlock != nil) disposeBlock();
  62. }
  63. #pragma mark Scoped Disposables
  64. - (RACScopedDisposable *)asScopedDisposable {
  65. return [RACScopedDisposable scopedDisposableWithDisposable:self];
  66. }
  67. @end