@@ -30,7 +30,7 @@ @interface BACancelToken ()
30
30
@property (nonatomic , strong ) dispatch_queue_t queue;
31
31
@property (nonatomic ) BAPromiseState promiseState;
32
32
@property (atomic ) BOOL cancelled;
33
- @property (nonatomic , strong ) dispatch_block_t onCancel;
33
+ @property (nonatomic , copy ) dispatch_block_t onCancel;
34
34
@end
35
35
36
36
@implementation BACancelToken
@@ -59,7 +59,7 @@ -(void)cancelled:(dispatch_block_t)onCancel
59
59
if (self.cancelled ) {
60
60
wrappedCancelBlock ();
61
61
} else {
62
- _onCancel = wrappedCancelBlock;
62
+ self. onCancel = wrappedCancelBlock;
63
63
}
64
64
}
65
65
});
@@ -69,7 +69,6 @@ -(void)cancel
69
69
{
70
70
self.cancelled = YES ;
71
71
dispatch_async (self.queue , ^{
72
-
73
72
if (self.onCancel ) {
74
73
self.onCancel ();
75
74
self.onCancel =nil ;
@@ -78,11 +77,42 @@ -(void)cancel
78
77
}
79
78
@end
80
79
80
+ @interface BAPromiseBlocks : NSObject
81
+ @property (nonatomic , copy ) BAPromiseOnFulfilledBlock done;
82
+ @property (nonatomic , copy ) BAPromiseOnFulfilledBlock observed;
83
+ @property (nonatomic , copy ) BAPromiseOnRejectedBlock rejected;
84
+ @property (nonatomic , copy ) BAPromiseFinallyBlock finally;
85
+ @end
86
+
87
+ @implementation BAPromiseBlocks
88
+ - (BOOL )shouldKeepPromise
89
+ {
90
+ return self.done != nil || self.finally != nil ;
91
+ }
92
+
93
+ - (void )callBlocksWithObject : (id )object
94
+ {
95
+ if ([object isKindOfClass: NSError .class]) {
96
+ if (self.rejected ) {
97
+ self.rejected (object);
98
+ }
99
+ } else {
100
+ if (self.done ) {
101
+ self.done (object);
102
+ }
103
+ if (self.observed ) {
104
+ self.observed (object);
105
+ }
106
+ }
107
+ if (self.finally ) {
108
+ self.finally ();
109
+ }
110
+ }
111
+ @end
112
+
113
+
81
114
@interface BAPromise ()
82
- @property (nonatomic , strong ) NSMutableArray *doneBlocks;
83
- @property (nonatomic , strong ) NSMutableArray *observerBlocks;
84
- @property (nonatomic , strong ) NSMutableArray *rejectedBlocks;
85
- @property (nonatomic , strong ) NSMutableArray *finallyBlocks;
115
+ @property (nonatomic , strong ) NSMutableArray <BAPromiseBlocks *> *blocks;
86
116
@property (nonatomic , strong ) id fulfilledObject;
87
117
@end
88
118
@@ -118,15 +148,14 @@ -(BACancelToken *)done:(BAPromiseOnFulfilledBlock)onFulfilled
118
148
BAPromiseOnRejectedBlock wrappedRejectedBlock;
119
149
BAPromiseFinallyBlock wrappedFinallyBlock;
120
150
121
- BACancelToken *cancellationToken;
122
-
123
- cancellationToken = [BACancelToken new ];
151
+ BACancelToken *cancellationToken = [BACancelToken new ];
124
152
153
+ __weak typeof (self) weakSelf = self;
125
154
// wrap the passed in blocks to dispatch to the appropriate queue and check for cancellaltion
126
155
if (onFulfilled) {
127
156
wrappedDoneBlock = ^(id obj) {
128
157
if (thread) {
129
- [self performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
158
+ [weakSelf performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
130
159
if (!cancellationToken.cancelled ) {
131
160
onFulfilled (obj);
132
161
}
@@ -144,7 +173,7 @@ -(BACancelToken *)done:(BAPromiseOnFulfilledBlock)onFulfilled
144
173
if (onObserved) {
145
174
wrappedObservedBlock = ^(id obj) {
146
175
if (thread) {
147
- [thread performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
176
+ [weakSelf performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
148
177
if (!cancellationToken.cancelled ) {
149
178
onObserved (obj);
150
179
}
@@ -162,7 +191,7 @@ -(BACancelToken *)done:(BAPromiseOnFulfilledBlock)onFulfilled
162
191
if (onRejected) {
163
192
wrappedRejectedBlock = ^(id obj) {
164
193
if (thread) {
165
- [thread performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
194
+ [weakSelf performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
166
195
if (!cancellationToken.cancelled ) {
167
196
onRejected (obj);
168
197
}
@@ -180,7 +209,7 @@ -(BACancelToken *)done:(BAPromiseOnFulfilledBlock)onFulfilled
180
209
if (onFinally) {
181
210
wrappedFinallyBlock = ^{
182
211
if (thread) {
183
- [thread performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
212
+ [weakSelf performSelector: @selector (ba_runBlock: ) onThread: thread withObject: ^{
184
213
if (!cancellationToken.cancelled ) {
185
214
onFinally ();
186
215
}
@@ -194,91 +223,49 @@ -(BACancelToken *)done:(BAPromiseOnFulfilledBlock)onFulfilled
194
223
}
195
224
};
196
225
}
226
+ BAPromiseBlocks *blocks = BAPromiseBlocks.new ;
227
+ blocks.done = wrappedDoneBlock;
228
+ blocks.observed = wrappedObservedBlock;
229
+ blocks.rejected = wrappedRejectedBlock;
230
+ blocks.finally = wrappedFinallyBlock;
197
231
198
232
[cancellationToken cancelled: ^{
199
- dispatch_async (self.queue , ^{
200
- if (onFulfilled) {
201
- [self .doneBlocks removeObjectIdenticalTo: wrappedDoneBlock];
202
- }
203
-
204
- if (onObserved) {
205
- [self .observerBlocks removeObjectIdenticalTo: wrappedObservedBlock];
206
- }
207
-
208
- if (onRejected) {
209
- [self .rejectedBlocks removeObjectIdenticalTo: wrappedRejectedBlock];
210
- }
211
-
212
- if (onFinally) {
213
- [self .finallyBlocks removeObjectIdenticalTo: wrappedFinallyBlock];
214
- }
215
-
216
- if (self.doneBlocks .count == 0
217
- && self.finallyBlocks .count == 0 ) {
218
- [self cancel ];
219
- }
220
- });
233
+ typeof (self) strongSelf = weakSelf;
234
+ if (strongSelf) {
235
+ dispatch_async (strongSelf.queue , ^{
236
+ @autoreleasepool {
237
+ [strongSelf.blocks removeObjectIdenticalTo: blocks];
238
+
239
+ BOOL strongCount = NO ;
240
+ for (BAPromiseBlocks *block in strongSelf.blocks ) {
241
+ if ([block shouldKeepPromise ]) {
242
+ strongCount = YES ;
243
+ break ;
244
+ }
245
+ }
246
+ if (!strongCount) {
247
+ [strongSelf cancel ];
248
+ }
249
+ }
250
+ });
251
+ }
221
252
}];
222
253
223
254
224
255
dispatch_async (self.queue , ^{
225
256
switch (self.promiseState ) {
226
257
case BAPromise_Unfulfilled:
227
- // save the blocks for later
228
- if (wrappedDoneBlock) {
229
- if (!_doneBlocks) {
230
- _doneBlocks = [[NSMutableArray alloc ] init ];
231
- }
232
- [_doneBlocks addObject: wrappedDoneBlock];
233
- }
234
-
235
- if (wrappedObservedBlock) {
236
- if (!_observerBlocks) {
237
- _observerBlocks = [[NSMutableArray alloc ] init ];
238
- }
239
- [_observerBlocks addObject: wrappedObservedBlock];
240
- }
241
-
242
- if (wrappedRejectedBlock) {
243
- if (!_rejectedBlocks) {
244
- _rejectedBlocks = [[NSMutableArray alloc ] init ];
245
- }
246
- [_rejectedBlocks addObject: wrappedRejectedBlock];
247
- }
248
-
249
- if (wrappedFinallyBlock) {
250
- if (!_finallyBlocks) {
251
- _finallyBlocks = [[NSMutableArray alloc ] init ];
252
- }
253
- [_finallyBlocks addObject: wrappedFinallyBlock];
258
+ // save the blocks for later
259
+ if (!self.blocks ) {
260
+ self.blocks = NSMutableArray .new ;
254
261
}
262
+ [self .blocks addObject: blocks];
255
263
break ;
256
264
257
265
case BAPromise_Fulfilled:
258
- if (wrappedDoneBlock) {
259
- // it was already fulfilled then call it now
260
- wrappedDoneBlock (_fulfilledObject);
261
- }
262
-
263
- if (wrappedObservedBlock) {
264
- wrappedObservedBlock (_fulfilledObject);
265
- }
266
-
267
- if (wrappedFinallyBlock) {
268
- wrappedFinallyBlock ();
269
- }
270
- break ;
271
-
272
266
case BAPromise_Rejected:
273
267
case BAPromise_Canceled:
274
- // if it was already rejected, but no failureBlock was set, then call it now
275
- if (wrappedRejectedBlock) {
276
- wrappedRejectedBlock (_fulfilledObject);
277
- }
278
-
279
- if (wrappedFinallyBlock) {
280
- wrappedFinallyBlock ();
281
- }
268
+ [blocks callBlocksWithObject: self .fulfilledObject];
282
269
break ;
283
270
}
284
271
});
@@ -504,23 +491,11 @@ -(void)fulfillWithObject:(id)obj
504
491
self.promiseState = BAPromise_Fulfilled;
505
492
self.fulfilledObject = obj;
506
493
507
- // remove references we'll never call now
508
- self.rejectedBlocks = nil ;
509
-
510
- for (BAPromiseOnFulfilledBlock done in self.doneBlocks ) {
511
- done (obj);
512
- }
513
- self.doneBlocks = nil ;
514
-
515
- for (BAPromiseOnFulfilledBlock done in self.observerBlocks ) {
516
- done (obj);
494
+ for (BAPromiseBlocks *blocks in self.blocks ) {
495
+ [blocks callBlocksWithObject: obj];
517
496
}
518
- self.observerBlocks = nil ;
519
-
520
- for (BAPromiseFinallyBlock finally in self.finallyBlocks ) {
521
- finally ();
522
- }
523
- self.finallyBlocks = nil ;
497
+ // remove references we'll never call now
498
+ self.blocks = nil ;
524
499
}
525
500
});
526
501
}
@@ -537,18 +512,11 @@ -(void)rejectWithError:(NSError *)error
537
512
if (self.promiseState == BAPromise_Unfulfilled) {
538
513
self.promiseState = BAPromise_Rejected;
539
514
self.fulfilledObject = error;
540
- // remove references we'll never call now
541
- self.doneBlocks = nil ;
542
- self.onCancel = nil ;
543
- for (BAPromiseOnRejectedBlock rejected in self.rejectedBlocks ) {
544
- rejected (error);
515
+ for (BAPromiseBlocks *blocks in self.blocks ) {
516
+ [blocks callBlocksWithObject: error];
545
517
}
546
- self.rejectedBlocks = nil ;
547
-
548
- for (BAPromiseFinallyBlock finally in self.finallyBlocks ) {
549
- finally ();
550
- }
551
- self.finallyBlocks = nil ;
518
+ // remove references we'll never call now
519
+ self.blocks = nil ;
552
520
}
553
521
});
554
522
}
@@ -557,6 +525,7 @@ -(void)reject
557
525
{
558
526
[self rejectWithError: [[NSError alloc ] init ]];
559
527
}
528
+
560
529
@end
561
530
562
531
@implementation NSArray (BAPromiseJoin)
0 commit comments