@@ -86,6 +86,10 @@ public class Task<Progress, Value, Error>
86
86
internal typealias Machine = StateMachine < TaskState , TaskEvent >
87
87
88
88
internal var machine : Machine !
89
+
90
+ // store initial parameters for cloning task when using `try()`
91
+ internal let _weakified : Bool
92
+ internal var _initClosure : _InitClosure ? // will be nil on fulfilled/rejected
89
93
90
94
/// progress value
91
95
public internal( set) var progress : Progress ?
@@ -122,11 +126,14 @@ public class Task<Progress, Value, Error>
122
126
///
123
127
public init ( weakified: Bool , initClosure: InitClosure )
124
128
{
125
- self . setup ( weakified) { ( progress, fulfill, _reject: ErrorInfo -> Void , configure) in
129
+ self . _weakified = weakified
130
+ self . _initClosure = { ( progress, fulfill, _reject: _RejectHandler , configure) in
126
131
// NOTE: don't expose rejectHandler with ErrorInfo (isCancelled) for public init
127
132
initClosure ( progress: progress, fulfill: fulfill, reject: { ( error: Error ? ) in _reject ( ErrorInfo ( error: error, isCancelled: false ) ) } , configure: configure)
128
133
return
129
134
}
135
+
136
+ self . setup ( weakified, self . _initClosure!)
130
137
}
131
138
132
139
/// creates task without weakifying progress/fulfill/reject handlers
@@ -162,13 +169,21 @@ public class Task<Progress, Value, Error>
162
169
} )
163
170
}
164
171
165
- internal init ( _initClosure: _InitClosure )
172
+ /// NOTE: _initClosure has _RejectHandler as argument
173
+ internal init ( weakified: Bool = false , _initClosure: _InitClosure )
166
174
{
167
- self . setup ( false , _initClosure)
175
+ self . _weakified = weakified
176
+ self . _initClosure = _initClosure
177
+
178
+ self . setup ( weakified, _initClosure)
168
179
}
169
180
170
181
internal func setup( weakified: Bool , _initClosure: _InitClosure )
171
182
{
183
+ #if DEBUG
184
+ println ( " [init] \( self ) " )
185
+ #endif
186
+
172
187
let configuration = Configuration ( )
173
188
174
189
weak var weakSelf = self
@@ -192,32 +207,36 @@ public class Task<Progress, Value, Error>
192
207
return
193
208
}
194
209
210
+ // NOTE: use order = 90 (< default = 100) to prepare setting value before handling progress/fulfill/reject
195
211
$0. addEventHandler ( . Progress, order: 90 ) { context in
196
212
if let progressTuple = context. userInfo as? ProgressTuple {
197
- if let self_ = weakSelf {
198
- self_. progress = progressTuple. newProgress
199
- }
213
+ weakSelf? . progress = progressTuple. newProgress
200
214
}
201
215
}
202
-
203
216
$0. addEventHandler ( . Fulfill, order: 90 ) { context in
204
217
if let value = context. userInfo as? Value {
205
- if let self_ = weakSelf {
206
- self_. value = value
207
- }
218
+ weakSelf? . value = value
208
219
}
209
220
configuration. clear ( )
210
221
}
211
222
$0. addEventHandler ( . Reject, order: 90 ) { context in
212
223
if let errorInfo = context. userInfo as? ErrorInfo {
213
- if let self_ = weakSelf {
214
- self_. errorInfo = errorInfo
215
- }
224
+ weakSelf? . errorInfo = errorInfo
216
225
configuration. cancel ? ( ) // NOTE: call configured cancellation on reject as well
217
226
}
218
227
configuration. clear ( )
219
228
}
220
229
230
+ // clear `_initClosure` after fulfilled/rejected to prevent retain cycle
231
+ $0. addEventHandler ( . Fulfill, order: 255 ) { context in
232
+ weakSelf? . _initClosure = nil
233
+ return
234
+ }
235
+ $0. addEventHandler ( . Reject, order: 255 ) { context in
236
+ weakSelf? . _initClosure = nil
237
+ return
238
+ }
239
+
221
240
}
222
241
223
242
var progressHandler : ProgressHandler
@@ -268,12 +287,36 @@ public class Task<Progress, Value, Error>
268
287
269
288
deinit
270
289
{
271
- // println("deinit: \(self)")
290
+ // #if DEBUG
291
+ // println("[deinit] \(self)")
292
+ // #endif
272
293
273
294
// cancel in case machine is still running
274
295
self . _cancel ( error: nil )
275
296
}
276
297
298
+ /// Returns new task that is retryable for `tryCount-1` times.
299
+ /// `task.try(n)` is conceptually equal to `task.failure(clonedTask1).failure(clonedTask2)...` with n-1 failure-able.
300
+ public func try( tryCount: Int ) -> Task
301
+ {
302
+ if tryCount < 2 { return self }
303
+
304
+ let weakified = self . _weakified
305
+ let initClosure = self . _initClosure
306
+
307
+ if initClosure == nil { return self }
308
+
309
+ var nextTask : Task ? = self
310
+
311
+ for i in 1 ... tryCount- 1 {
312
+ nextTask = nextTask!. failure { _ -> Task in
313
+ return Task ( weakified: weakified, _initClosure: initClosure!) // create a clone-task when rejected
314
+ }
315
+ }
316
+
317
+ return nextTask!
318
+ }
319
+
277
320
public func progress( progressClosure: ProgressTuple -> Void ) -> Task
278
321
{
279
322
self . machine. addEventHandler ( . Progress) { [ weak self] context in
@@ -631,6 +674,20 @@ extension Task
631
674
}
632
675
}
633
676
677
+ //--------------------------------------------------
678
+ // MARK: - Custom Operators
679
+ // + - * / % = < > ! & | ^ ~ .
680
+ //--------------------------------------------------
681
+
682
+ infix operator ~ { associativity left }
683
+
684
+ /// abbreviation for `try()`
685
+ /// e.g. (task ~ 3).then { ... }
686
+ public func ~ < P, V, E> ( task: Task < P , V , E > , tryCount: Int ) -> Task < P , V , E >
687
+ {
688
+ return task. try ( tryCount)
689
+ }
690
+
634
691
//--------------------------------------------------
635
692
// MARK: - Utility
636
693
//--------------------------------------------------
0 commit comments