RACDisposable.m 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 [(RACDisposable *)[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