RACSerialDisposable.m 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // RACSerialDisposable.m
  3. // ReactiveObjC
  4. //
  5. // Created by Justin Spahr-Summers on 2013-07-22.
  6. // Copyright (c) 2013 GitHub, Inc. All rights reserved.
  7. //
  8. #import "RACSerialDisposable.h"
  9. #import <pthread/pthread.h>
  10. @interface RACSerialDisposable () {
  11. // The receiver's `disposable`. This variable must only be referenced while
  12. // _mutex is held.
  13. RACDisposable * _disposable;
  14. // YES if the receiver has been disposed. This variable must only be accessed
  15. // while _mutex is held.
  16. BOOL _disposed;
  17. // A mutex to protect access to _disposable and _disposed.
  18. pthread_mutex_t _mutex;
  19. }
  20. @end
  21. @implementation RACSerialDisposable
  22. #pragma mark Properties
  23. - (BOOL)isDisposed {
  24. pthread_mutex_lock(&_mutex);
  25. const BOOL disposed = _disposed;
  26. pthread_mutex_unlock(&_mutex);
  27. return disposed;
  28. }
  29. - (RACDisposable *)disposable {
  30. pthread_mutex_lock(&_mutex);
  31. RACDisposable * const result = _disposable;
  32. pthread_mutex_unlock(&_mutex);
  33. return result;
  34. }
  35. - (void)setDisposable:(RACDisposable *)disposable {
  36. [self swapInDisposable:disposable];
  37. }
  38. #pragma mark Lifecycle
  39. + (instancetype)serialDisposableWithDisposable:(RACDisposable *)disposable {
  40. RACSerialDisposable *serialDisposable = [[self alloc] init];
  41. serialDisposable.disposable = disposable;
  42. return serialDisposable;
  43. }
  44. - (instancetype)init {
  45. self = [super init];
  46. if (self == nil) return nil;
  47. const int result __attribute__((unused)) = pthread_mutex_init(&_mutex, NULL);
  48. NSCAssert(0 == result, @"Failed to initialize mutex with error %d", result);
  49. return self;
  50. }
  51. - (instancetype)initWithBlock:(void (^)(void))block {
  52. self = [self init];
  53. if (self == nil) return nil;
  54. self.disposable = [RACDisposable disposableWithBlock:block];
  55. return self;
  56. }
  57. - (void)dealloc {
  58. const int result __attribute__((unused)) = pthread_mutex_destroy(&_mutex);
  59. NSCAssert(0 == result, @"Failed to destroy mutex with error %d", result);
  60. }
  61. #pragma mark Inner Disposable
  62. - (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable {
  63. RACDisposable *existingDisposable;
  64. BOOL alreadyDisposed;
  65. pthread_mutex_lock(&_mutex);
  66. alreadyDisposed = _disposed;
  67. if (!alreadyDisposed) {
  68. existingDisposable = _disposable;
  69. _disposable = newDisposable;
  70. }
  71. pthread_mutex_unlock(&_mutex);
  72. if (alreadyDisposed) {
  73. [newDisposable dispose];
  74. return nil;
  75. }
  76. return existingDisposable;
  77. }
  78. #pragma mark Disposal
  79. - (void)dispose {
  80. RACDisposable *existingDisposable;
  81. pthread_mutex_lock(&_mutex);
  82. if (!_disposed) {
  83. existingDisposable = _disposable;
  84. _disposed = YES;
  85. _disposable = nil;
  86. }
  87. pthread_mutex_unlock(&_mutex);
  88. [existingDisposable dispose];
  89. }
  90. @end