@@ -65,14 +65,14 @@ public class TaskConfiguration
6565 }
6666}
6767
68- // abstract class for `weak _parentTask`
68+ // abstract class for `weak _parentTask` with arbitrary `Progress` & `Value` types
6969public class _Task < Error>
7070{
7171 internal weak var _parentTask : _Task ?
7272
7373 internal let _weakified : Bool
7474
75- public init ( weakified: Bool ) { self . _weakified = weakified }
75+ public init ( weakified: Bool , paused : Bool ) { self . _weakified = weakified }
7676 public func pause( ) -> Bool { return true }
7777 public func resume( ) -> Bool { return true }
7878 public func cancel( error: Error ? = nil ) -> Bool { return true }
@@ -98,11 +98,14 @@ public class Task<Progress, Value, Error>: _Task<Error>
9898
9999 internal typealias Machine = StateMachine < TaskState , TaskEvent >
100100
101- internal var machine : Machine !
101+ private var machine : Machine !
102102
103103 // store initial parameters for cloning task when using `try()`
104104 internal var _initClosure : _InitClosure ? // will be nil on fulfilled/rejected
105105
106+ /// wrapper closure for `_initClosure` to invoke only once when started `.Running`
107+ internal var _performInitClosure : ( Void -> Void ) ?
108+
106109 /// progress value
107110 public internal( set) var progress : Progress ?
108111
@@ -127,84 +130,109 @@ public class Task<Progress, Value, Error>: _Task<Error>
127130 }
128131
129132 ///
130- /// Creates new task.
133+ /// Creates a new task.
131134 ///
132- /// - e.g. Task<P, V, E>(weakified: false) { progress, fulfill, reject, configure in ... }
135+ /// - e.g. Task<P, V, E>(weakified: false, paused: false ) { progress, fulfill, reject, configure in ... }
133136 ///
134137 /// :param: weakified Weakifies progress/fulfill/reject handlers to let player (inner asynchronous implementation inside initClosure) NOT CAPTURE this created new task. Normally, weakified = false should be set to gain "player -> task" retaining, so that task will be automatically deinited when player is deinited. If weakified = true, task must be manually retained somewhere else, or it will be immediately deinited.
135138 ///
139+ /// :param: paused Flag to invoke `initClosure` immediately or not. If `paused = true`, task's initial state will be `.Paused` and needs to `resume()` in order to start `.Running`. If `paused = false`, `initClosure` will be invoked immediately.
140+ ///
136141 /// :param: initClosure e.g. { progress, fulfill, reject, configure in ... }. fulfill(value) and reject(error) handlers must be called inside this closure, where calling progress(progressValue) handler is optional. Also as options, configure.pause/resume/cancel closures can be set to gain control from outside e.g. task.pause()/resume()/cancel(). When using configure, make sure to use weak modifier when appropriate to avoid "task -> player" retaining which often causes retain cycle.
137142 ///
138143 /// :returns: New task.
139144 ///
140- public init ( weakified: Bool , initClosure: InitClosure )
145+ public init ( weakified: Bool , paused : Bool , initClosure: InitClosure )
141146 {
142- super. init ( weakified: weakified)
147+ super. init ( weakified: weakified, paused : paused )
143148
144149 let _initClosure : _InitClosure = { machine, progress, fulfill, _reject, configure in
145150 // NOTE: don't expose rejectHandler with ErrorInfo (isCancelled) for public init
146151 initClosure ( progress: progress, fulfill: fulfill, reject: { ( error: Error ? ) in _reject ( ErrorInfo ( error: error, isCancelled: false ) ) } , configure: configure)
147- return
148152 }
149153
150- self . setup ( weakified, _initClosure)
154+ self . setup ( weakified, paused : paused , _initClosure)
151155 }
152156
153- /// creates task without weakifying progress/fulfill/reject handlers
157+ ///
158+ /// creates a new task without weakifying progress/fulfill/reject handlers
159+ ///
160+ /// - e.g. Task<P, V, E>(paused: false) { progress, fulfill, reject, configure in ... }
161+ ///
162+ public convenience init ( paused: Bool , initClosure: InitClosure )
163+ {
164+ self . init ( weakified: false , paused: paused, initClosure: initClosure)
165+ }
166+
167+ ///
168+ /// creates a new task without weakifying progress/fulfill/reject handlers (non-paused)
169+ ///
170+ /// - e.g. Task<P, V, E> { progress, fulfill, reject, configure in ... }
171+ ///
154172 public convenience init ( initClosure: InitClosure )
155173 {
156- self . init ( weakified: false , initClosure: initClosure)
174+ self . init ( weakified: false , paused : false , initClosure: initClosure)
157175 }
158176
159- /// creates fulfilled task
177+ ///
178+ /// creates fulfilled task (non-paused)
179+ ///
180+ /// - e.g. Task<P, V, E>(value: someValue)
181+ ///
160182 public convenience init ( value: Value )
161183 {
162184 self . init ( initClosure: { progress, fulfill, reject, configure in
163185 fulfill ( value)
164- return
165186 } )
166187 }
167188
168- /// creates rejected task
189+ ///
190+ /// creates rejected task (non-paused)
191+ ///
192+ /// - e.g. Task<P, V, E>(error: someError)
193+ ///
169194 public convenience init ( error: Error )
170195 {
171196 self . init ( initClosure: { progress, fulfill, reject, configure in
172197 reject ( error)
173- return
174198 } )
175199 }
176200
201+ ///
177202 /// creates promise-like task which only allows fulfill & reject (no progress & configure)
203+ ///
204+ /// - e.g. Task<Any, Value, Error> { fulfill, reject in ... }
205+ ///
178206 public convenience init ( promiseInitClosure: PromiseInitClosure )
179207 {
180208 self . init ( initClosure: { progress, fulfill, reject, configure in
181209 promiseInitClosure ( fulfill: fulfill, reject: { ( error: Error ) in reject ( error) } )
182- return
183210 } )
184211 }
185212
186- /// NOTE: _initClosure has _RejectHandler as argument
187- internal init ( weakified: Bool = false , _initClosure: _InitClosure )
213+ /// internal-init for accessing private `machine` inside `_initClosure`
214+ /// (NOTE: _initClosure has _RejectHandler as argument)
215+ internal init ( weakified: Bool = false , paused: Bool = false , _initClosure: _InitClosure )
188216 {
189- super. init ( weakified: weakified)
190- self . setup ( weakified, _initClosure)
217+ super. init ( weakified: weakified, paused : paused )
218+ self . setup ( weakified, paused : paused , _initClosure)
191219 }
192220
193- internal func setup( weakified: Bool , _initClosure: _InitClosure )
221+ internal func setup( weakified: Bool , paused : Bool , _initClosure: _InitClosure )
194222 {
195223// #if DEBUG
196224// println("[init] \(self)")
197225// #endif
198226
199- self . _initClosure = _initClosure
200-
201227 let configuration = Configuration ( )
202228
229+ let initialState : TaskState = paused ? . Paused : . Running
230+
203231 // NOTE: Swift 1.1 compiler fails if using [weak self] instead...
204232 weak var weakSelf = self
205233
206234 // setup state machine
207- self . machine = Machine ( state: . Running ) {
235+ self . machine = Machine ( state: initialState ) {
208236
209237 $0. addRouteEvent ( . Pause, transitions: [ . Running => . Paused] )
210238 $0. addRouteEvent ( . Resume, transitions: [ . Paused => . Running] )
@@ -245,97 +273,114 @@ public class Task<Progress, Value, Error>: _Task<Error>
245273 // clear `_initClosure` & all StateMachine's handlers to prevent retain cycle
246274 $0. addEventHandler ( . Fulfill, order: 255 ) { context in
247275 weakSelf? . _initClosure = nil
276+ weakSelf? . _performInitClosure = nil
248277 weakSelf? . machine? . removeAllHandlers ( )
249278 }
250279 $0. addEventHandler ( . Reject, order: 255 ) { context in
251280 weakSelf? . _initClosure = nil
281+ weakSelf? . _performInitClosure = nil
252282 weakSelf? . machine? . removeAllHandlers ( )
253283 }
254284
255285 }
256286
257- var progressHandler : ProgressHandler
258- var fulfillHandler : FulFillHandler
259- var rejectHandler : _RejectHandler
287+ self . _initClosure = _initClosure
260288
261- if weakified {
262- progressHandler = { [ weak self] ( progress: Progress ) in
263- if let self_ = self {
264- let oldProgress = self_. progress
265- self_. machine <-! ( . Progress, ( oldProgress, progress) )
266- }
267- }
289+ // will be invoked only once
290+ self . _performInitClosure = { [ weak self] in
268291
269- fulfillHandler = { [ weak self] ( value: Value ) in
270- if let self_ = self {
271- self_. machine <-! ( . Fulfill, value)
292+ if let self_ = self {
293+
294+ var progressHandler : ProgressHandler
295+ var fulfillHandler : FulFillHandler
296+ var rejectHandler : _RejectHandler
297+
298+ if weakified {
299+ progressHandler = { [ weak self_] ( progress: Progress ) in
300+ if let self_ = self_ {
301+ let oldProgress = self_. progress
302+ self_. machine <-! ( . Progress, ( oldProgress, progress) )
303+ }
304+ }
305+
306+ fulfillHandler = { [ weak self_] ( value: Value ) in
307+ if let self_ = self_ {
308+ self_. machine <-! ( . Fulfill, value)
309+ }
310+ }
311+
312+ rejectHandler = { [ weak self_] ( errorInfo: ErrorInfo ) in
313+ if let self_ = self_ {
314+ self_. machine <-! ( . Reject, errorInfo)
315+ }
316+ }
272317 }
273- }
274-
275- rejectHandler = { [ weak self] ( errorInfo: ErrorInfo ) in
276- if let self_ = self {
277- self_. machine <-! ( . Reject, errorInfo)
318+ else {
319+ progressHandler = { ( progress: Progress ) in
320+ let oldProgress = self_. progress
321+ self_. machine <-! ( . Progress, ( oldProgress, progress) )
322+ return
323+ }
324+
325+ fulfillHandler = { ( value: Value ) in
326+ self_. machine <-! ( . Fulfill, value)
327+ return
328+ }
329+
330+ rejectHandler = { ( errorInfo: ErrorInfo ) in
331+ self_. machine <-! ( . Reject, errorInfo)
332+ return
333+ }
278334 }
279- }
280- }
281- else {
282- progressHandler = { ( progress: Progress ) in
283- let oldProgress = self . progress
284- self . machine <-! ( . Progress, ( oldProgress, progress) )
285- return
286- }
287335
288- fulfillHandler = { ( value: Value ) in
289- self . machine <-! ( . Fulfill, value)
290- return
291- }
292-
293- rejectHandler = { ( errorInfo: ErrorInfo ) in
294- self . machine <-! ( . Reject, errorInfo)
295- return
296- }
297- }
298-
299- _initClosure ( machine: self . machine, progress: progressHandler, fulfill: fulfillHandler, _reject: rejectHandler, configure: configuration)
300-
301- let userPauseClosure = configuration. pause
302- let userResumeClosure = configuration. resume
303- let userCancelClosure = configuration. cancel
304-
305- // add parentTask-pause/resume/cancel functionalities after retrieving user-defined configuration
306- configuration. pause = { [ weak self] in
307- userPauseClosure ? ( )
308-
309- var task : _Task ? = self
310- while let parentTask = task? . _parentTask {
311- if parentTask. _weakified { break }
336+ _initClosure ( machine: self_. machine, progress: progressHandler, fulfill: fulfillHandler, _reject: rejectHandler, configure: configuration)
312337
313- parentTask. pause ( )
314- task = parentTask
315- }
316-
317- }
318- configuration. resume = { [ weak self] in
319- userResumeClosure ? ( )
320-
321- var task : _Task ? = self
322- while let parentTask = task? . _parentTask {
323- if parentTask. _weakified { break }
338+ let userPauseClosure = configuration. pause
339+ let userResumeClosure = configuration. resume
340+ let userCancelClosure = configuration. cancel
324341
325- parentTask. resume ( )
326- task = parentTask
327- }
328- }
329- configuration. cancel = { [ weak self] in
330- userCancelClosure ? ( )
331-
332- var task : _Task ? = self
333- while let parentTask = task? . _parentTask {
334- if parentTask. _weakified { break }
342+ // add parentTask-pause/resume/cancel functionalities after retrieving user-defined configuration
343+ configuration. pause = { [ weak self_] in
344+ userPauseClosure ? ( )
345+
346+ var task : _Task ? = self_
347+ while let parentTask = task? . _parentTask {
348+ if parentTask. _weakified { break }
349+
350+ parentTask. pause ( )
351+ task = parentTask
352+ }
353+
354+ }
355+ configuration. resume = { [ weak self_] in
356+ userResumeClosure ? ( )
357+
358+ var task : _Task ? = self_
359+ while let parentTask = task? . _parentTask {
360+ if parentTask. _weakified { break }
361+
362+ parentTask. resume ( )
363+ task = parentTask
364+ }
365+ }
366+ configuration. cancel = { [ weak self_] in
367+ userCancelClosure ? ( )
368+
369+ var task : _Task ? = self_
370+ while let parentTask = task? . _parentTask {
371+ if parentTask. _weakified { break }
372+
373+ parentTask. cancel ( )
374+ task = parentTask
375+ }
376+ }
335377
336- parentTask. cancel ( )
337- task = parentTask
338378 }
379+
380+ }
381+
382+ if !paused {
383+ self . resume ( )
339384 }
340385 }
341386
@@ -672,6 +717,11 @@ public class Task<Progress, Value, Error>: _Task<Error>
672717
673718 public override func resume( ) -> Bool
674719 {
720+ // always try `_performInitClosure` only once on `resume()`
721+ // even when to-Resume-transition fails, e.g. already been fulfilled/rejected
722+ self . _performInitClosure ? ( )
723+ self . _performInitClosure = nil
724+
675725 return self . machine <-! . Resume
676726 }
677727
0 commit comments