@@ -57,7 +57,7 @@ public class TaskConfiguration
5757 }
5858}
5959
60- public class Task < Progress, Value, Error> : Printable
60+ public class Task < Progress, Value, Error> : Cancellable , Printable
6161{
6262 public typealias ProgressTuple = ( oldProgress: Progress ? , newProgress: Progress )
6363 public typealias ErrorInfo = ( error: Error ? , isCancelled: Bool )
@@ -213,7 +213,8 @@ public class Task<Progress, Value, Error>: Printable
213213 internal func setup( #weakified: Bool, paused: Bool, _initClosure: _InitClosure)
214214 {
215215// #if DEBUG
216- // println("[init] \(self.name)")
216+ // let addr = String(format: "%p", unsafeAddressOf(self))
217+ // NSLog("[init] \(self.name) \(addr)")
217218// #endif
218219
219220 self . _initClosure = _initClosure
@@ -287,7 +288,8 @@ public class Task<Progress, Value, Error>: Printable
287288 deinit
288289 {
289290// #if DEBUG
290- // println("[deinit] \(self.name)")
291+ // let addr = String(format: "%p", unsafeAddressOf(self))
292+ // NSLog("[deinit] \(self.name) \(addr)")
291293// #endif
292294
293295 // cancel in case machine is still running
@@ -355,31 +357,62 @@ public class Task<Progress, Value, Error>: Printable
355357 ///
356358 public func progress( progressClosure: ProgressTuple -> Void ) -> Task
357359 {
358- self . _machine. addProgressTupleHandler ( progressClosure)
360+ var dummyCanceller : Canceller ? = nil
361+ return self . progress ( & dummyCanceller, progressClosure)
362+ }
363+
364+ public func progress< C: Canceller > ( inout canceller: C ? , _ progressClosure: ProgressTuple -> Void ) -> Task
365+ {
366+ var token : _HandlerToken ? = nil
367+ self . _machine. addProgressTupleHandler ( & token, progressClosure)
368+
369+ canceller = C { [ weak self] in
370+ self ? . _machine. removeProgressTupleHandler ( token)
371+ }
359372
360373 return self
361374 }
362375
363376 ///
364- /// then (fulfilled & rejected) + closure returning value
377+ /// then (fulfilled & rejected) + closure returning **value**
378+ /// (a.k.a. `map` in functional programming term)
365379 ///
366380 /// - e.g. task.then { value, errorInfo -> NextValueType in ... }
367381 ///
368382 public func then< Value2> ( thenClosure: ( Value ? , ErrorInfo ? ) -> Value2 ) -> Task < Progress , Value2 , Error >
369383 {
370- return self . then { ( value: Value ? , errorInfo: ErrorInfo ? ) -> Task < Progress , Value2 , Error > in
384+ var dummyCanceller : Canceller ? = nil
385+ return self . then ( & dummyCanceller, thenClosure)
386+ }
387+
388+ public func then< Value2, C: Canceller > ( inout canceller: C ? , _ thenClosure: ( Value ? , ErrorInfo ? ) -> Value2 ) -> Task < Progress , Value2 , Error >
389+ {
390+ return self . then ( & canceller) { ( value: Value ? , errorInfo: ErrorInfo ? ) -> Task < Progress , Value2 , Error > in
371391 return Task < Progress , Value2 , Error > ( value: thenClosure ( value, errorInfo) )
372392 }
373393 }
374394
375395 ///
376- /// then (fulfilled & rejected) + closure returning task
396+ /// then (fulfilled & rejected) + closure returning **task**
397+ /// (a.k.a. `flatMap` in functional programming term)
377398 ///
378399 /// - e.g. task.then { value, errorInfo -> NextTaskType in ... }
379400 ///
380401 public func then< Progress2, Value2> ( thenClosure: ( Value ? , ErrorInfo ? ) -> Task < Progress2 , Value2 , Error > ) -> Task < Progress2 , Value2 , Error >
381402 {
382- return Task < Progress2 , Value2 , Error > { [ unowned self] newMachine, progress, fulfill, _reject, configure in
403+ var dummyCanceller : Canceller ? = nil
404+ return self . then ( & dummyCanceller, thenClosure)
405+ }
406+
407+ //
408+ // NOTE: then-canceller is a shorthand of `task.cancel(nil)`, i.e. these two are the same:
409+ //
410+ // - `let canceller = Canceller(); task1.then(&canceller) {...}; canceller.cancel();`
411+ // - `let task2 = task1.then {...}; task2.cancel();`
412+ //
413+ public func then< Progress2, Value2, C: Canceller > ( inout canceller: C ? , _ thenClosure: ( Value ? , ErrorInfo ? ) -> Task < Progress2 , Value2 , Error > ) -> Task < Progress2 , Value2 , Error >
414+ {
415+ return Task < Progress2 , Value2 , Error > { [ unowned self, weak canceller] newMachine, progress, fulfill, _reject, configure in
383416
384417 //
385418 // NOTE:
@@ -389,8 +422,8 @@ public class Task<Progress, Value, Error>: Printable
389422 // This is especially important for ReactKit's `deinitSignal` behavior.
390423 //
391424 let selfMachine = self . _machine
392-
393- self . _then {
425+
426+ self . _then ( & canceller ) {
394427 let innerTask = thenClosure ( selfMachine. value, selfMachine. errorInfo)
395428 _bindInnerTask ( innerTask, newMachine, progress, fulfill, _reject, configure)
396429 }
@@ -399,41 +432,58 @@ public class Task<Progress, Value, Error>: Printable
399432 }
400433
401434 /// invokes `completionHandler` "now" or "in the future"
402- private func _then( completionHandler: Void -> Void )
435+ private func _then< C : Canceller > ( inout canceller : C ? , _ completionHandler: Void -> Void )
403436 {
404437 switch self . state {
405438 case . Fulfilled, . Rejected, . Cancelled:
406439 completionHandler ( )
407440 default :
408- self . _machine. addCompletionHandler ( completionHandler)
441+ var token : _HandlerToken ? = nil
442+ self . _machine. addCompletionHandler ( & token, completionHandler)
443+
444+ canceller = C { [ weak self] in
445+ self ? . _machine. removeCompletionHandler ( token)
446+ }
409447 }
410448 }
411449
412450 ///
413- /// success (fulfilled) + closure returning value
451+ /// success (fulfilled) + closure returning ** value**
414452 ///
415453 /// - e.g. task.success { value -> NextValueType in ... }
416454 ///
417455 public func success< Value2> ( successClosure: Value -> Value2 ) -> Task < Progress , Value2 , Error >
418456 {
419- return self . success { ( value: Value ) -> Task < Progress , Value2 , Error > in
457+ var dummyCanceller : Canceller ? = nil
458+ return self . success ( & dummyCanceller, successClosure)
459+ }
460+
461+ public func success< Value2, C: Canceller > ( inout canceller: C ? , _ successClosure: Value -> Value2 ) -> Task < Progress , Value2 , Error >
462+ {
463+ return self . success ( & canceller) { ( value: Value ) -> Task < Progress , Value2 , Error > in
420464 return Task < Progress , Value2 , Error > ( value: successClosure ( value) )
421465 }
422466 }
423467
424468 ///
425- /// success (fulfilled) + closure returning task
469+ /// success (fulfilled) + closure returning ** task**
426470 ///
427471 /// - e.g. task.success { value -> NextTaskType in ... }
428472 ///
429473 public func success< Progress2, Value2> ( successClosure: Value -> Task < Progress2 , Value2 , Error > ) -> Task < Progress2 , Value2 , Error >
474+ {
475+ var dummyCanceller : Canceller ? = nil
476+ return self . success ( & dummyCanceller, successClosure)
477+ }
478+
479+ public func success< Progress2, Value2, C: Canceller > ( inout canceller: C ? , _ successClosure: Value -> Task < Progress2 , Value2 , Error > ) -> Task < Progress2 , Value2 , Error >
430480 {
431481 return Task < Progress2 , Value2 , Error > { [ unowned self] newMachine, progress, fulfill, _reject, configure in
432482
433483 let selfMachine = self . _machine
434484
435485 // NOTE: using `self._then()` + `selfMachine` instead of `self.then()` will reduce Task allocation
436- self . _then {
486+ self . _then ( & canceller ) {
437487 if let value = selfMachine. value {
438488 let innerTask = successClosure ( value)
439489 _bindInnerTask ( innerTask, newMachine, progress, fulfill, _reject, configure)
@@ -447,31 +497,43 @@ public class Task<Progress, Value, Error>: Printable
447497 }
448498
449499 ///
450- /// failure (rejected) + closure returning value
500+ /// failure (rejected or cancelled ) + closure returning ** value**
451501 ///
452502 /// - e.g. task.failure { errorInfo -> NextValueType in ... }
453503 /// - e.g. task.failure { error, isCancelled -> NextValueType in ... }
454504 ///
455505 public func failure( failureClosure: ErrorInfo -> Value ) -> Task
456506 {
457- return self . failure { ( errorInfo: ErrorInfo ) -> Task in
507+ var dummyCanceller : Canceller ? = nil
508+ return self . failure ( & dummyCanceller, failureClosure)
509+ }
510+
511+ public func failure< C: Canceller > ( inout canceller: C ? , _ failureClosure: ErrorInfo -> Value ) -> Task
512+ {
513+ return self . failure ( & canceller) { ( errorInfo: ErrorInfo ) -> Task in
458514 return Task ( value: failureClosure ( errorInfo) )
459515 }
460516 }
461517
462518 ///
463- /// failure (rejected) + closure returning task
519+ /// failure (rejected or cancelled ) + closure returning ** task**
464520 ///
465521 /// - e.g. task.failure { errorInfo -> NextTaskType in ... }
466522 /// - e.g. task.failure { error, isCancelled -> NextTaskType in ... }
467523 ///
468524 public func failure< Progress2> ( failureClosure: ErrorInfo -> Task < Progress2 , Value , Error > ) -> Task < Progress2 , Value , Error >
525+ {
526+ var dummyCanceller : Canceller ? = nil
527+ return self . failure ( & dummyCanceller, failureClosure)
528+ }
529+
530+ public func failure< Progress2, C: Canceller > ( inout canceller: C ? , _ failureClosure: ErrorInfo -> Task < Progress2 , Value , Error > ) -> Task < Progress2 , Value , Error >
469531 {
470532 return Task < Progress2 , Value , Error > { [ unowned self] newMachine, progress, fulfill, _reject, configure in
471533
472534 let selfMachine = self . _machine
473535
474- self . _then {
536+ self . _then ( & canceller ) {
475537 if let value = selfMachine. value {
476538 fulfill ( value)
477539 }
@@ -494,7 +556,18 @@ public class Task<Progress, Value, Error>: Printable
494556 return self . _machine. handleResume ( )
495557 }
496558
497- public func cancel( error: Error ? = nil ) -> Bool
559+ //
560+ // NOTE:
561+ // To conform to `Cancellable`, this method is needed in replace of:
562+ // - `public func cancel(error: Error? = nil) -> Bool`
563+ // - `public func cancel(_ error: Error? = nil) -> Bool` (segfault in Swift 1.2)
564+ //
565+ public func cancel( ) -> Bool
566+ {
567+ return self . cancel ( error: nil )
568+ }
569+
570+ public func cancel( #error: Error?) -> Bool
498571 {
499572 return self . _cancel ( error: error)
500573 }
@@ -503,6 +576,7 @@ public class Task<Progress, Value, Error>: Printable
503576 {
504577 return self . _machine. handleCancel ( error: error)
505578 }
579+
506580}
507581
508582// MARK: - Helper
0 commit comments