forked from Lightricks/ReactiveObjC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRACDisposable.m
90 lines (65 loc) · 1.83 KB
/
RACDisposable.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//
// RACDisposable.m
// ReactiveObjC
//
// Created by Josh Abernathy on 3/16/12.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACDisposable.h"
#import "RACScopedDisposable.h"
#import <stdatomic.h>
@interface RACDisposable () {
// A copied block of type void (^)(void) containing the logic for disposal,
// a pointer to `self` if no logic should be performed upon disposal, or
// NULL if the receiver is already disposed.
//
// This should only be used atomically.
_Atomic(void *) _disposeBlock;
}
@end
@implementation RACDisposable
#pragma mark Properties
- (BOOL)isDisposed {
return _disposeBlock == NULL;
}
#pragma mark Lifecycle
- (instancetype)init {
self = [super init];
_disposeBlock = (__bridge void *)self;
atomic_thread_fence(memory_order_seq_cst);
return self;
}
- (instancetype)initWithBlock:(void (^)(void))block {
NSCParameterAssert(block != nil);
self = [super init];
_disposeBlock = (void *)CFBridgingRetain([block copy]);
atomic_thread_fence(memory_order_seq_cst);
return self;
}
+ (instancetype)disposableWithBlock:(void (^)(void))block {
return [[self alloc] initWithBlock:block];
}
- (void)dealloc {
if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;
CFRelease(_disposeBlock);
_disposeBlock = NULL;
}
#pragma mark Disposal
- (void)dispose {
void (^disposeBlock)(void) = NULL;
while (YES) {
void *blockPtr = _disposeBlock;
if (atomic_compare_exchange_strong(&_disposeBlock, &blockPtr, NULL)) {
if (blockPtr != (__bridge void *)self) {
disposeBlock = CFBridgingRelease(blockPtr);
}
break;
}
}
if (disposeBlock != nil) disposeBlock();
}
#pragma mark Scoped Disposables
- (RACScopedDisposable *)asScopedDisposable {
return [RACScopedDisposable scopedDisposableWithDisposable:self];
}
@end