@@ -65,7 +65,18 @@ public class TaskConfiguration
6565 }
6666}
6767
68- public class Task < Progress, Value, Error>
68+ // abstract class for `weak _parentTask`
69+ public class _Task < Error>
70+ {
71+ internal weak var _parentTask : _Task ?
72+
73+ public init ( ) { }
74+ public func pause( ) -> Bool { return true }
75+ public func resume( ) -> Bool { return true }
76+ public func cancel( error: Error ? = nil ) -> Bool { return true }
77+ }
78+
79+ public class Task < Progress, Value, Error> : _Task < Error >
6980{
7081 public typealias ErrorInfo = ( error: Error ? , isCancelled: Bool )
7182
@@ -81,7 +92,7 @@ public class Task<Progress, Value, Error>
8192 public typealias InitClosure = ( progress: ProgressHandler , fulfill: FulFillHandler , reject: RejectHandler , configure: TaskConfiguration ) -> Void
8293
8394 internal typealias _RejectHandler = ( ErrorInfo ) -> Void
84- internal typealias _InitClosure = ( progress: ProgressHandler , fulfill: FulFillHandler , _reject: _RejectHandler , configure: TaskConfiguration ) -> Void
95+ internal typealias _InitClosure = ( machine : Machine , progress: ProgressHandler , fulfill: FulFillHandler , _reject: _RejectHandler , configure: TaskConfiguration ) -> Void
8596
8697 internal typealias Machine = StateMachine < TaskState , TaskEvent >
8798
@@ -90,7 +101,7 @@ public class Task<Progress, Value, Error>
90101 // store initial parameters for cloning task when using `try()`
91102 internal let _weakified : Bool
92103 internal var _initClosure : _InitClosure ? // will be nil on fulfilled/rejected
93-
104+
94105 /// progress value
95106 public internal( set) var progress : Progress ?
96107
@@ -127,12 +138,13 @@ public class Task<Progress, Value, Error>
127138 public init ( weakified: Bool , initClosure: InitClosure )
128139 {
129140 self . _weakified = weakified
130- self . _initClosure = { ( progress, fulfill, _reject: _RejectHandler , configure) in
141+ self . _initClosure = { machine , progress, fulfill, _reject, configure in
131142 // NOTE: don't expose rejectHandler with ErrorInfo (isCancelled) for public init
132143 initClosure ( progress: progress, fulfill: fulfill, reject: { ( error: Error ? ) in _reject ( ErrorInfo ( error: error, isCancelled: false ) ) } , configure: configure)
133144 return
134145 }
135146
147+ super. init ( )
136148 self . setup ( weakified, self . _initClosure!)
137149 }
138150
@@ -175,14 +187,15 @@ public class Task<Progress, Value, Error>
175187 self . _weakified = weakified
176188 self . _initClosure = _initClosure
177189
190+ super. init ( )
178191 self . setup ( weakified, _initClosure)
179192 }
180193
181194 internal func setup( weakified: Bool , _initClosure: _InitClosure )
182195 {
183- #if DEBUG
184- println ( " [init] \( self ) " )
185- #endif
196+ // #if DEBUG
197+ // println("[init] \(self)")
198+ // #endif
186199
187200 let configuration = Configuration ( )
188201
@@ -227,14 +240,14 @@ public class Task<Progress, Value, Error>
227240 configuration. clear ( )
228241 }
229242
230- // clear `_initClosure` after fulfilled/rejected to prevent retain cycle
243+ // clear `_initClosure` & all StateMachine's handlers to prevent retain cycle
231244 $0. addEventHandler ( . Fulfill, order: 255 ) { context in
232245 weakSelf? . _initClosure = nil
233- return
246+ weakSelf ? . machine ? . removeAllHandlers ( )
234247 }
235248 $0. addEventHandler ( . Reject, order: 255 ) { context in
236249 weakSelf? . _initClosure = nil
237- return
250+ weakSelf ? . machine ? . removeAllHandlers ( )
238251 }
239252
240253 }
@@ -281,7 +294,41 @@ public class Task<Progress, Value, Error>
281294 }
282295 }
283296
284- _initClosure ( progress: progressHandler, fulfill: fulfillHandler, _reject: rejectHandler, configure: configuration)
297+ _initClosure ( machine: self . machine, progress: progressHandler, fulfill: fulfillHandler, _reject: rejectHandler, configure: configuration)
298+
299+ let userPauseClosure = configuration. pause
300+ let userResumeClosure = configuration. resume
301+ let userCancelClosure = configuration. cancel
302+
303+ // add parentTask-pause/resume/cancel functionalities after retrieving user-defined configuration
304+ configuration. pause = { [ weak self] in
305+ userPauseClosure ? ( )
306+
307+ var task : _Task ? = self
308+ while let parentTask = task? . _parentTask {
309+ parentTask. pause ( )
310+ task = parentTask
311+ }
312+
313+ }
314+ configuration. resume = { [ weak self] in
315+ userResumeClosure ? ( )
316+
317+ var task : _Task ? = self
318+ while let parentTask = task? . _parentTask {
319+ parentTask. resume ( )
320+ task = parentTask
321+ }
322+ }
323+ configuration. cancel = { [ weak self] in
324+ userCancelClosure ? ( )
325+
326+ var task : _Task ? = self
327+ while let parentTask = task? . _parentTask {
328+ parentTask. cancel ( )
329+ task = parentTask
330+ }
331+ }
285332
286333 }
287334
@@ -339,9 +386,9 @@ public class Task<Progress, Value, Error>
339386 /// then (fulfilled & rejected) + closure returning task
340387 public func then< Progress2, Value2> ( thenClosure: ( Value ? , ErrorInfo ? ) -> Task < Progress2 , Value2 , Error > ) -> Task < Progress2 , Value2 , Error >
341388 {
342- let newTask = Task < Progress2 , Value2 , Error > { ( progress, fulfill, _reject: _RejectHandler , configure) in
389+ let newTask = Task < Progress2 , Value2 , Error > { machine , progress, fulfill, _reject, configure in
343390
344- let bind = { ( value: Value ? , errorInfo: ErrorInfo ? ) -> Void in
391+ let bind = { [ weak machine ] ( value: Value ? , errorInfo: ErrorInfo ? ) -> Void in
345392 let innerTask = thenClosure ( value, errorInfo)
346393
347394 // NOTE: don't call `then` for innerTask, or recursive bindings may occur
@@ -352,6 +399,11 @@ public class Task<Progress, Value, Error>
352399 case . Rejected:
353400 _reject ( innerTask. errorInfo!)
354401 default :
402+ innerTask. machine. addEventHandler ( . Progress) { context in
403+ if let ( _, progressValue) = context. userInfo as? Task < Progress2 , Value2 , Error > . ProgressTuple {
404+ progress ( progressValue)
405+ }
406+ }
355407 innerTask. machine. addEventHandler ( . Fulfill) { context in
356408 if let value = context. userInfo as? Value2 {
357409 fulfill ( value)
@@ -367,6 +419,14 @@ public class Task<Progress, Value, Error>
367419 configure. pause = { innerTask. pause ( ) ; return }
368420 configure. resume = { innerTask. resume ( ) ; return }
369421 configure. cancel = { innerTask. cancel ( ) ; return }
422+
423+ // pause/cancel innerTask if descendant task is already paused/cancelled
424+ if machine!. state == . Paused {
425+ innerTask. pause ( )
426+ }
427+ else if machine!. state == . Cancelled {
428+ innerTask. cancel ( )
429+ }
370430 }
371431
372432 switch self . machine. state {
@@ -375,6 +435,11 @@ public class Task<Progress, Value, Error>
375435 case . Rejected:
376436 bind ( nil , self . errorInfo!)
377437 default :
438+ self . machine. addEventHandler ( . Progress) { context in
439+ if let ( _, progressValue) = context. userInfo as? Task < Progress2 , Value2 , Error > . ProgressTuple {
440+ progress ( progressValue)
441+ }
442+ }
378443 self . machine. addEventHandler ( . Fulfill) { context in
379444 if let value = context. userInfo as? Value {
380445 bind ( value, nil )
@@ -389,6 +454,8 @@ public class Task<Progress, Value, Error>
389454
390455 }
391456
457+ newTask. _parentTask = self
458+
392459 return newTask
393460 }
394461
@@ -403,12 +470,14 @@ public class Task<Progress, Value, Error>
403470 /// success (fulfilled) + closure returning task
404471 public func success< Progress2, Value2> ( successClosure: Value -> Task < Progress2 , Value2 , Error > ) -> Task < Progress2 , Value2 , Error >
405472 {
406- let newTask = Task < Progress2 , Value2 , Error > { ( progress, fulfill, _reject: _RejectHandler , configure) in
473+ let newTask = Task < Progress2 , Value2 , Error > { machine , progress, fulfill, _reject, configure in
407474
408- let bind = { ( value: Value ) -> Void in
475+ let bind = { [ weak machine ] ( value: Value ) -> Void in
409476 let innerTask = successClosure ( value)
410477
411- innerTask. then { ( value: Value2 ? , errorInfo: ErrorInfo ? ) -> Void in
478+ innerTask. progress { _, progressValue in
479+ progress ( progressValue)
480+ } . then { ( value: Value2 ? , errorInfo: ErrorInfo ? ) -> Void in
412481 if let value = value {
413482 fulfill ( value)
414483 }
@@ -420,6 +489,14 @@ public class Task<Progress, Value, Error>
420489 configure. pause = { innerTask. pause ( ) ; return }
421490 configure. resume = { innerTask. resume ( ) ; return }
422491 configure. cancel = { innerTask. cancel ( ) ; return }
492+
493+ // pause/cancel innerTask if descendant task is already paused/cancelled
494+ if machine!. state == . Paused {
495+ innerTask. pause ( )
496+ }
497+ else if machine!. state == . Cancelled {
498+ innerTask. cancel ( )
499+ }
423500 }
424501
425502 switch self . machine. state {
@@ -428,6 +505,11 @@ public class Task<Progress, Value, Error>
428505 case . Rejected:
429506 _reject ( self . errorInfo!)
430507 default :
508+ self . machine. addEventHandler ( . Progress) { context in
509+ if let ( _, progressValue) = context. userInfo as? Task < Progress2 , Value2 , Error > . ProgressTuple {
510+ progress ( progressValue)
511+ }
512+ }
431513 self . machine. addEventHandler ( . Fulfill) { context in
432514 if let value = context. userInfo as? Value {
433515 bind ( value)
@@ -442,6 +524,8 @@ public class Task<Progress, Value, Error>
442524
443525 }
444526
527+ newTask. _parentTask = self
528+
445529 return newTask
446530 }
447531
@@ -456,12 +540,14 @@ public class Task<Progress, Value, Error>
456540 /// failure (rejected) + closure returning task
457541 public func failure( failureClosure: ErrorInfo -> Task ) -> Task
458542 {
459- let newTask = Task { ( progress, fulfill, _reject: _RejectHandler , configure) in
543+ let newTask = Task { machine , progress, fulfill, _reject, configure in
460544
461- let bind = { ( errorInfo: ErrorInfo ) -> Void in
545+ let bind = { [ weak machine ] ( errorInfo: ErrorInfo ) -> Void in
462546 let innerTask = failureClosure ( errorInfo)
463547
464- innerTask. then { ( value: Value ? , errorInfo: ErrorInfo ? ) -> Void in
548+ innerTask. progress { _, progressValue in
549+ progress ( progressValue)
550+ } . then { ( value: Value ? , errorInfo: ErrorInfo ? ) -> Void in
465551 if let value = value {
466552 fulfill ( value)
467553 }
@@ -472,7 +558,15 @@ public class Task<Progress, Value, Error>
472558
473559 configure. pause = { innerTask. pause ( ) ; return }
474560 configure. resume = { innerTask. resume ( ) ; return }
475- configure. cancel = { innerTask. cancel ( ) ; return }
561+ configure. cancel = { innerTask. cancel ( ) ; return }
562+
563+ // pause/cancel innerTask if descendant task is already paused/cancelled
564+ if machine!. state == . Paused {
565+ innerTask. pause ( )
566+ }
567+ else if machine!. state == . Cancelled {
568+ innerTask. cancel ( )
569+ }
476570 }
477571
478572 switch self . machine. state {
@@ -482,6 +576,11 @@ public class Task<Progress, Value, Error>
482576 let errorInfo = self . errorInfo!
483577 bind ( errorInfo)
484578 default :
579+ self . machine. addEventHandler ( . Progress) { context in
580+ if let ( _, progressValue) = context. userInfo as? Task . ProgressTuple {
581+ progress ( progressValue)
582+ }
583+ }
485584 self . machine. addEventHandler ( . Fulfill) { context in
486585 if let value = context. userInfo as? Value {
487586 fulfill ( value)
@@ -496,20 +595,22 @@ public class Task<Progress, Value, Error>
496595
497596 }
498597
598+ newTask. _parentTask = self
599+
499600 return newTask
500601 }
501602
502- public func pause( ) -> Bool
603+ public override func pause( ) -> Bool
503604 {
504605 return self . machine <-! . Pause
505606 }
506607
507- public func resume( ) -> Bool
608+ public override func resume( ) -> Bool
508609 {
509610 return self . machine <-! . Resume
510611 }
511612
512- public func cancel( error: Error ? = nil ) -> Bool
613+ public override func cancel( error: Error ? = nil ) -> Bool
513614 {
514615 return self . _cancel ( error: error)
515616 }
@@ -524,7 +625,7 @@ extension Task
524625{
525626 public class func all( tasks: [ Task ] ) -> Task < BulkProgress , [ Value ] , Error >
526627 {
527- return Task < BulkProgress , [ Value ] , Error > { ( progress, fulfill, _reject: _RejectHandler , configure) in
628+ return Task < BulkProgress , [ Value ] , Error > { machine , progress, fulfill, _reject, configure in
528629
529630 var completedCount = 0
530631 let totalCount = tasks. count
@@ -570,7 +671,7 @@ extension Task
570671
571672 public class func any( tasks: [ Task ] ) -> Task
572673 {
573- return Task < Progress , Value , Error > { ( progress, fulfill, _reject: _RejectHandler , configure) in
674+ return Task < Progress , Value , Error > { machine , progress, fulfill, _reject, configure in
574675
575676 var completedCount = 0
576677 var rejectedCount = 0
@@ -615,7 +716,7 @@ extension Task
615716 /// This new task will NEVER be internally rejected.
616717 public class func some( tasks: [ Task ] ) -> Task < BulkProgress , [ Value ] , Error >
617718 {
618- return Task < BulkProgress , [ Value ] , Error > { ( progress, fulfill, _reject: _RejectHandler , configure) in
719+ return Task < BulkProgress , [ Value ] , Error > { machine , progress, fulfill, _reject, configure in
619720
620721 var completedCount = 0
621722 let totalCount = tasks. count
0 commit comments