RACDisposable.m 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //
  2. // RACDisposable.m
  3. // ReactiveObjC
  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. - (instancetype)init {
  27. self = [super init];
  28. _disposeBlock = (__bridge void *)self;
  29. OSMemoryBarrier();
  30. return self;
  31. }
  32. - (instancetype)initWithBlock:(void (^)(void))block {
  33. NSCParameterAssert(block != nil);
  34. self = [super init];
  35. _disposeBlock = (void *)CFBridgingRetain([block copy]);
  36. OSMemoryBarrier();
  37. return self;
  38. }
  39. + (instancetype)disposableWithBlock:(void (^)(void))block {
  40. return [[self alloc] initWithBlock:block];
  41. }
  42. - (void)dealloc {
  43. if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;
  44. CFRelease(_disposeBlock);
  45. _disposeBlock = NULL;
  46. }
  47. #pragma mark Disposal
  48. - (void)dispose {
  49. void (^disposeBlock)(void) = NULL;
  50. while (YES) {
  51. void *blockPtr = _disposeBlock;
  52. if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
  53. if (blockPtr != (__bridge void *)self) {
  54. disposeBlock = CFBridgingRelease(blockPtr);
  55. }
  56. break;
  57. }
  58. }
  59. if (disposeBlock != nil) disposeBlock();
  60. }
  61. #pragma mark Scoped Disposables
  62. - (RACScopedDisposable *)asScopedDisposable {
  63. return [RACScopedDisposable scopedDisposableWithDisposable:self];
  64. }
  65. @end