123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- //
- // RACSerialDisposable.m
- // ReactiveObjC
- //
- // Created by Justin Spahr-Summers on 2013-07-22.
- // Copyright (c) 2013 GitHub, Inc. All rights reserved.
- //
- #import "RACSerialDisposable.h"
- #import <pthread/pthread.h>
- @interface RACSerialDisposable () {
- // The receiver's `disposable`. This variable must only be referenced while
- // _mutex is held.
- RACDisposable * _disposable;
- // YES if the receiver has been disposed. This variable must only be accessed
- // while _mutex is held.
- BOOL _disposed;
- // A mutex to protect access to _disposable and _disposed.
- pthread_mutex_t _mutex;
- }
- @end
- @implementation RACSerialDisposable
- #pragma mark Properties
- - (BOOL)isDisposed {
- pthread_mutex_lock(&_mutex);
- const BOOL disposed = _disposed;
- pthread_mutex_unlock(&_mutex);
- return disposed;
- }
- - (RACDisposable *)disposable {
- pthread_mutex_lock(&_mutex);
- RACDisposable * const result = _disposable;
- pthread_mutex_unlock(&_mutex);
- return result;
- }
- - (void)setDisposable:(RACDisposable *)disposable {
- [self swapInDisposable:disposable];
- }
- #pragma mark Lifecycle
- + (instancetype)serialDisposableWithDisposable:(RACDisposable *)disposable {
- RACSerialDisposable *serialDisposable = [[self alloc] init];
- serialDisposable.disposable = disposable;
- return serialDisposable;
- }
- - (instancetype)init {
- self = [super init];
- if (self == nil) return nil;
- const int result __attribute__((unused)) = pthread_mutex_init(&_mutex, NULL);
- NSCAssert(0 == result, @"Failed to initialize mutex with error %d", result);
- return self;
- }
- - (instancetype)initWithBlock:(void (^)(void))block {
- self = [self init];
- if (self == nil) return nil;
- self.disposable = [RACDisposable disposableWithBlock:block];
- return self;
- }
- - (void)dealloc {
- const int result __attribute__((unused)) = pthread_mutex_destroy(&_mutex);
- NSCAssert(0 == result, @"Failed to destroy mutex with error %d", result);
- }
- #pragma mark Inner Disposable
- - (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable {
- RACDisposable *existingDisposable;
- BOOL alreadyDisposed;
- pthread_mutex_lock(&_mutex);
- alreadyDisposed = _disposed;
- if (!alreadyDisposed) {
- existingDisposable = _disposable;
- _disposable = newDisposable;
- }
- pthread_mutex_unlock(&_mutex);
- if (alreadyDisposed) {
- [newDisposable dispose];
- return nil;
- }
- return existingDisposable;
- }
- #pragma mark Disposal
- - (void)dispose {
- RACDisposable *existingDisposable;
- pthread_mutex_lock(&_mutex);
- if (!_disposed) {
- existingDisposable = _disposable;
- _disposed = YES;
- _disposable = nil;
- }
- pthread_mutex_unlock(&_mutex);
-
- [existingDisposable dispose];
- }
- @end
|