@@ -86,6 +86,10 @@ public class Task<Progress, Value, Error>
8686 internal typealias Machine = StateMachine < TaskState , TaskEvent >
8787
8888 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
8993
9094 /// progress value
9195 public internal( set) var progress : Progress ?
@@ -122,11 +126,14 @@ public class Task<Progress, Value, Error>
122126 ///
123127 public init ( weakified: Bool , initClosure: InitClosure )
124128 {
125- self . setup ( weakified) { ( progress, fulfill, _reject: ErrorInfo -> Void , configure) in
129+ self . _weakified = weakified
130+ self . _initClosure = { ( progress, fulfill, _reject: _RejectHandler , configure) in
126131 // NOTE: don't expose rejectHandler with ErrorInfo (isCancelled) for public init
127132 initClosure ( progress: progress, fulfill: fulfill, reject: { ( error: Error ? ) in _reject ( ErrorInfo ( error: error, isCancelled: false ) ) } , configure: configure)
128133 return
129134 }
135+
136+ self . setup ( weakified, self . _initClosure!)
130137 }
131138
132139 /// creates task without weakifying progress/fulfill/reject handlers
@@ -162,13 +169,21 @@ public class Task<Progress, Value, Error>
162169 } )
163170 }
164171
165- internal init ( _initClosure: _InitClosure )
172+ /// NOTE: _initClosure has _RejectHandler as argument
173+ internal init ( weakified: Bool = false , _initClosure: _InitClosure )
166174 {
167- self . setup ( false , _initClosure)
175+ self . _weakified = weakified
176+ self . _initClosure = _initClosure
177+
178+ self . setup ( weakified, _initClosure)
168179 }
169180
170181 internal func setup( weakified: Bool , _initClosure: _InitClosure )
171182 {
183+ #if DEBUG
184+ println ( " [init] \( self ) " )
185+ #endif
186+
172187 let configuration = Configuration ( )
173188
174189 weak var weakSelf = self
@@ -192,32 +207,36 @@ public class Task<Progress, Value, Error>
192207 return
193208 }
194209
210+ // NOTE: use order = 90 (< default = 100) to prepare setting value before handling progress/fulfill/reject
195211 $0. addEventHandler ( . Progress, order: 90 ) { context in
196212 if let progressTuple = context. userInfo as? ProgressTuple {
197- if let self_ = weakSelf {
198- self_. progress = progressTuple. newProgress
199- }
213+ weakSelf? . progress = progressTuple. newProgress
200214 }
201215 }
202-
203216 $0. addEventHandler ( . Fulfill, order: 90 ) { context in
204217 if let value = context. userInfo as? Value {
205- if let self_ = weakSelf {
206- self_. value = value
207- }
218+ weakSelf? . value = value
208219 }
209220 configuration. clear ( )
210221 }
211222 $0. addEventHandler ( . Reject, order: 90 ) { context in
212223 if let errorInfo = context. userInfo as? ErrorInfo {
213- if let self_ = weakSelf {
214- self_. errorInfo = errorInfo
215- }
224+ weakSelf? . errorInfo = errorInfo
216225 configuration. cancel ? ( ) // NOTE: call configured cancellation on reject as well
217226 }
218227 configuration. clear ( )
219228 }
220229
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+
221240 }
222241
223242 var progressHandler : ProgressHandler
@@ -268,12 +287,36 @@ public class Task<Progress, Value, Error>
268287
269288 deinit
270289 {
271- // println("deinit: \(self)")
290+ // #if DEBUG
291+ // println("[deinit] \(self)")
292+ // #endif
272293
273294 // cancel in case machine is still running
274295 self . _cancel ( error: nil )
275296 }
276297
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+
277320 public func progress( progressClosure: ProgressTuple -> Void ) -> Task
278321 {
279322 self . machine. addEventHandler ( . Progress) { [ weak self] context in
@@ -631,6 +674,20 @@ extension Task
631674 }
632675}
633676
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+
634691//--------------------------------------------------
635692// MARK: - Utility
636693//--------------------------------------------------
0 commit comments