Skip to content

Commit 8a22ed5

Browse files
committed
Remove removeProgress() & removeThen(), add Cancellable instead.
1 parent 16a2e60 commit 8a22ed5

File tree

6 files changed

+146
-89
lines changed

6 files changed

+146
-89
lines changed

SwiftTask.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
1FCF71141AD8CD2F007079C2 /* Async.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FCF71131AD8CD2F007079C2 /* Async.framework */; };
2121
1FCF71161AD8CD38007079C2 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FCF71151AD8CD38007079C2 /* Alamofire.framework */; };
2222
1FCF71181AD8CD3C007079C2 /* Async.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FCF71171AD8CD3C007079C2 /* Async.framework */; };
23+
1FD7197B1AFE387C00BC38C4 /* Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD7197A1AFE387C00BC38C4 /* Cancellable.swift */; };
24+
1FD7197C1AFE387C00BC38C4 /* Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD7197A1AFE387C00BC38C4 /* Cancellable.swift */; };
2325
1FF52EB41A4C395A00B4BA28 /* _InterruptableTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF52EB31A4C395A00B4BA28 /* _InterruptableTask.swift */; };
2426
1FF52EB51A4C395A00B4BA28 /* _InterruptableTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF52EB31A4C395A00B4BA28 /* _InterruptableTask.swift */; };
2527
4822F0DC19D00B2300F5F572 /* _TestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F46DEFC199EE2C200F97868 /* _TestCase.swift */; };
@@ -53,6 +55,7 @@
5355
1FCF71131AD8CD2F007079C2 /* Async.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Async.framework; path = "../Carthage/Checkouts/Async/build/Debug-iphoneos/Async.framework"; sourceTree = "<group>"; };
5456
1FCF71151AD8CD38007079C2 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = ../Carthage/Checkouts/Alamofire/build/Debug/Alamofire.framework; sourceTree = "<group>"; };
5557
1FCF71171AD8CD3C007079C2 /* Async.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Async.framework; path = ../Carthage/Checkouts/Async/build/Debug/Async.framework; sourceTree = "<group>"; };
58+
1FD7197A1AFE387C00BC38C4 /* Cancellable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cancellable.swift; sourceTree = "<group>"; };
5659
1FF52EB31A4C395A00B4BA28 /* _InterruptableTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _InterruptableTask.swift; sourceTree = "<group>"; };
5760
4822F0D019D00ABF00F5F572 /* SwiftTask-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftTask-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
5861
48511C5A19C17563002FE03C /* RetainCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RetainCycleTests.swift; sourceTree = "<group>"; };
@@ -124,6 +127,7 @@
124127
children = (
125128
1F46DED9199EDF1000F97868 /* SwiftTask.h */,
126129
1F46DEFA199EDF8100F97868 /* SwiftTask.swift */,
130+
1FD7197A1AFE387C00BC38C4 /* Cancellable.swift */,
127131
48B58D7A1A6F255E0068E18C /* _StateMachine.swift */,
128132
1F46DED7199EDF1000F97868 /* Supporting Files */,
129133
);
@@ -339,6 +343,7 @@
339343
buildActionMask = 2147483647;
340344
files = (
341345
1F46DEFB199EDF8100F97868 /* SwiftTask.swift in Sources */,
346+
1FD7197B1AFE387C00BC38C4 /* Cancellable.swift in Sources */,
342347
48B58D7B1A6F255E0068E18C /* _StateMachine.swift in Sources */,
343348
);
344349
runOnlyForDeploymentPostprocessing = 0;
@@ -378,6 +383,7 @@
378383
buildActionMask = 2147483647;
379384
files = (
380385
48CD5A3C19AEEBDF0042B9F1 /* SwiftTask.swift in Sources */,
386+
1FD7197C1AFE387C00BC38C4 /* Cancellable.swift in Sources */,
381387
48B58D7C1A6F255E0068E18C /* _StateMachine.swift in Sources */,
382388
);
383389
runOnlyForDeploymentPostprocessing = 0;

SwiftTask/Cancellable.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//
2+
// Cancellable.swift
3+
// SwiftTask
4+
//
5+
// Created by Yasuhiro Inami on 2015/05/09.
6+
// Copyright (c) 2015年 Yasuhiro Inami. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public protocol Cancellable
12+
{
13+
typealias Error
14+
15+
func cancel(error: Error) -> Bool
16+
}
17+
18+
public class Canceller: Cancellable
19+
{
20+
private var cancelHandler: (Void -> Void)?
21+
22+
public required init(cancelHandler: Void -> Void)
23+
{
24+
self.cancelHandler = cancelHandler
25+
}
26+
27+
public func cancel(error: Void) -> Bool
28+
{
29+
if let cancelHandler = self.cancelHandler {
30+
self.cancelHandler = nil
31+
cancelHandler()
32+
return true
33+
}
34+
35+
return false
36+
}
37+
}
38+
39+
public class AutoCanceller: Canceller
40+
{
41+
deinit
42+
{
43+
self.cancel()
44+
}
45+
}

SwiftTask/SwiftTask.swift

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -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,14 +357,19 @@ public class Task<Progress, Value, Error>: Printable
355357
///
356358
public func progress(progressClosure: ProgressTuple -> Void) -> Task
357359
{
358-
var token: HandlerToken? = nil
359-
return self.progress(&token, progressClosure)
360+
var dummyCanceller: Canceller? = nil
361+
return self.progress(&dummyCanceller, progressClosure)
360362
}
361363

362-
public func progress(inout token: HandlerToken?, _ progressClosure: ProgressTuple -> Void) -> Task
364+
public func progress<C: Canceller>(inout canceller: C?, _ progressClosure: ProgressTuple -> Void) -> Task
363365
{
366+
var token: _HandlerToken? = nil
364367
self._machine.addProgressTupleHandler(&token, progressClosure)
365368

369+
canceller = C { [weak self] in
370+
self?._machine.removeProgressTupleHandler(token)
371+
}
372+
366373
return self
367374
}
368375

@@ -373,13 +380,13 @@ public class Task<Progress, Value, Error>: Printable
373380
///
374381
public func then<Value2>(thenClosure: (Value?, ErrorInfo?) -> Value2) -> Task<Progress, Value2, Error>
375382
{
376-
var token: HandlerToken? = nil
377-
return self.then(&token, thenClosure)
383+
var dummyCanceller: Canceller? = nil
384+
return self.then(&dummyCanceller, thenClosure)
378385
}
379386

380-
public func then<Value2>(inout token: HandlerToken?, _ thenClosure: (Value?, ErrorInfo?) -> Value2) -> Task<Progress, Value2, Error>
387+
public func then<Value2, C: Canceller>(inout canceller: C?, _ thenClosure: (Value?, ErrorInfo?) -> Value2) -> Task<Progress, Value2, Error>
381388
{
382-
return self.then(&token) { (value: Value?, errorInfo: ErrorInfo?) -> Task<Progress, Value2, Error> in
389+
return self.then(&canceller) { (value: Value?, errorInfo: ErrorInfo?) -> Task<Progress, Value2, Error> in
383390
return Task<Progress, Value2, Error>(value: thenClosure(value, errorInfo))
384391
}
385392
}
@@ -391,13 +398,13 @@ public class Task<Progress, Value, Error>: Printable
391398
///
392399
public func then<Progress2, Value2>(thenClosure: (Value?, ErrorInfo?) -> Task<Progress2, Value2, Error>) -> Task<Progress2, Value2, Error>
393400
{
394-
var token: HandlerToken? = nil
395-
return self.then(&token, thenClosure)
401+
var dummyCanceller: Canceller? = nil
402+
return self.then(&dummyCanceller, thenClosure)
396403
}
397404

398-
public func then<Progress2, Value2>(inout token: HandlerToken?, _ thenClosure: (Value?, ErrorInfo?) -> Task<Progress2, Value2, Error>) -> Task<Progress2, Value2, Error>
405+
public func then<Progress2, Value2, C: Canceller>(inout canceller: C?, _ thenClosure: (Value?, ErrorInfo?) -> Task<Progress2, Value2, Error>) -> Task<Progress2, Value2, Error>
399406
{
400-
return Task<Progress2, Value2, Error> { [unowned self] newMachine, progress, fulfill, _reject, configure in
407+
return Task<Progress2, Value2, Error> { [unowned self, weak canceller] newMachine, progress, fulfill, _reject, configure in
401408

402409
//
403410
// NOTE:
@@ -408,7 +415,7 @@ public class Task<Progress, Value, Error>: Printable
408415
//
409416
let selfMachine = self._machine
410417

411-
self._then(&token) {
418+
self._then(&canceller) {
412419
let innerTask = thenClosure(selfMachine.value, selfMachine.errorInfo)
413420
_bindInnerTask(innerTask, newMachine, progress, fulfill, _reject, configure)
414421
}
@@ -417,13 +424,18 @@ public class Task<Progress, Value, Error>: Printable
417424
}
418425

419426
/// invokes `completionHandler` "now" or "in the future"
420-
private func _then(inout token: HandlerToken?, _ completionHandler: Void -> Void)
427+
private func _then<C: Canceller>(inout canceller: C?, _ completionHandler: Void -> Void)
421428
{
422429
switch self.state {
423430
case .Fulfilled, .Rejected, .Cancelled:
424431
completionHandler()
425432
default:
433+
var token: _HandlerToken? = nil
426434
self._machine.addCompletionHandler(&token, completionHandler)
435+
436+
canceller = C { [weak self] in
437+
self?._machine.removeCompletionHandler(token)
438+
}
427439
}
428440
}
429441

@@ -434,13 +446,13 @@ public class Task<Progress, Value, Error>: Printable
434446
///
435447
public func success<Value2>(successClosure: Value -> Value2) -> Task<Progress, Value2, Error>
436448
{
437-
var token: HandlerToken? = nil
438-
return self.success(&token, successClosure)
449+
var dummyCanceller: Canceller? = nil
450+
return self.success(&dummyCanceller, successClosure)
439451
}
440452

441-
public func success<Value2>(inout token: HandlerToken?, _ successClosure: Value -> Value2) -> Task<Progress, Value2, Error>
453+
public func success<Value2, C: Canceller>(inout canceller: C?, _ successClosure: Value -> Value2) -> Task<Progress, Value2, Error>
442454
{
443-
return self.success(&token) { (value: Value) -> Task<Progress, Value2, Error> in
455+
return self.success(&canceller) { (value: Value) -> Task<Progress, Value2, Error> in
444456
return Task<Progress, Value2, Error>(value: successClosure(value))
445457
}
446458
}
@@ -452,18 +464,18 @@ public class Task<Progress, Value, Error>: Printable
452464
///
453465
public func success<Progress2, Value2>(successClosure: Value -> Task<Progress2, Value2, Error>) -> Task<Progress2, Value2, Error>
454466
{
455-
var token: HandlerToken? = nil
456-
return self.success(&token, successClosure)
467+
var dummyCanceller: Canceller? = nil
468+
return self.success(&dummyCanceller, successClosure)
457469
}
458470

459-
public func success<Progress2, Value2>(inout token: HandlerToken?, _ successClosure: Value -> Task<Progress2, Value2, Error>) -> Task<Progress2, Value2, Error>
471+
public func success<Progress2, Value2, C: Canceller>(inout canceller: C?, _ successClosure: Value -> Task<Progress2, Value2, Error>) -> Task<Progress2, Value2, Error>
460472
{
461473
return Task<Progress2, Value2, Error> { [unowned self] newMachine, progress, fulfill, _reject, configure in
462474

463475
let selfMachine = self._machine
464476

465477
// NOTE: using `self._then()` + `selfMachine` instead of `self.then()` will reduce Task allocation
466-
self._then(&token) {
478+
self._then(&canceller) {
467479
if let value = selfMachine.value {
468480
let innerTask = successClosure(value)
469481
_bindInnerTask(innerTask, newMachine, progress, fulfill, _reject, configure)
@@ -484,13 +496,13 @@ public class Task<Progress, Value, Error>: Printable
484496
///
485497
public func failure(failureClosure: ErrorInfo -> Value) -> Task
486498
{
487-
var token: HandlerToken? = nil
488-
return self.failure(&token, failureClosure)
499+
var dummyCanceller: Canceller? = nil
500+
return self.failure(&dummyCanceller, failureClosure)
489501
}
490502

491-
public func failure(inout token: HandlerToken?, _ failureClosure: ErrorInfo -> Value) -> Task
503+
public func failure<C: Canceller>(inout canceller: C?, _ failureClosure: ErrorInfo -> Value) -> Task
492504
{
493-
return self.failure(&token) { (errorInfo: ErrorInfo) -> Task in
505+
return self.failure(&canceller) { (errorInfo: ErrorInfo) -> Task in
494506
return Task(value: failureClosure(errorInfo))
495507
}
496508
}
@@ -503,17 +515,17 @@ public class Task<Progress, Value, Error>: Printable
503515
///
504516
public func failure<Progress2>(failureClosure: ErrorInfo -> Task<Progress2, Value, Error>) -> Task<Progress2, Value, Error>
505517
{
506-
var token: HandlerToken? = nil
507-
return self.failure(&token, failureClosure)
518+
var dummyCanceller: Canceller? = nil
519+
return self.failure(&dummyCanceller, failureClosure)
508520
}
509521

510-
public func failure<Progress2>(inout token: HandlerToken?, _ failureClosure: ErrorInfo -> Task<Progress2, Value, Error>) -> Task<Progress2, Value, Error>
522+
public func failure<Progress2, C: Canceller>(inout canceller: C?, _ failureClosure: ErrorInfo -> Task<Progress2, Value, Error>) -> Task<Progress2, Value, Error>
511523
{
512524
return Task<Progress2, Value, Error> { [unowned self] newMachine, progress, fulfill, _reject, configure in
513525

514526
let selfMachine = self._machine
515527

516-
self._then(&token) {
528+
self._then(&canceller) {
517529
if let value = selfMachine.value {
518530
fulfill(value)
519531
}
@@ -536,27 +548,25 @@ public class Task<Progress, Value, Error>: Printable
536548
return self._machine.handleResume()
537549
}
538550

539-
public func cancel(error: Error? = nil) -> Bool
551+
//
552+
// NOTE:
553+
// To conform to `Cancellable`, this method is needed in replace of:
554+
// - `public func cancel(error: Error? = nil) -> Bool`
555+
// - `public func cancel(_ error: Error? = nil) -> Bool` (segfault in Swift 1.2)
556+
//
557+
public func cancel() -> Bool
540558
{
541-
return self._cancel(error: error)
559+
return self.cancel(nil)
542560
}
543561

544-
internal func _cancel(error: Error? = nil) -> Bool
562+
public func cancel(error: Error?) -> Bool
545563
{
546-
return self._machine.handleCancel(error: error)
547-
}
548-
549-
// MARK: Remove Handlers
550-
551-
public func removeProgress(handlerToken: HandlerToken)
552-
{
553-
return self._machine.removeProgressTupleHandler(handlerToken)
564+
return self._cancel(error: error)
554565
}
555566

556-
/// NOTE: `task.removeThen(token)` will force `let task2 = task.then(&token)` to deinit immediately and tries cancellation if it is still running.
557-
public func removeThen(handlerToken: HandlerToken)
567+
internal func _cancel(error: Error? = nil) -> Bool
558568
{
559-
return self._machine.removeCompletionHandler(handlerToken)
569+
return self._machine.handleCancel(error: error)
560570
}
561571

562572
}

SwiftTask/_StateMachine.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,32 @@ internal class _StateMachine<Progress, Value, Error>
4141
self.state = paused ? .Paused : .Running
4242
}
4343

44-
internal func addProgressTupleHandler(inout token: HandlerToken?, _ progressTupleHandler: ProgressTupleHandler)
44+
internal func addProgressTupleHandler(inout token: _HandlerToken?, _ progressTupleHandler: ProgressTupleHandler)
4545
{
4646
if self.state == .Running || self.state == .Paused {
4747
token = self.progressTupleHandlers.append(progressTupleHandler)
4848
}
4949
}
5050

51-
internal func removeProgressTupleHandler(handlerToken: HandlerToken)
51+
internal func removeProgressTupleHandler(handlerToken: _HandlerToken?)
5252
{
53-
self.progressTupleHandlers.remove(handlerToken)
53+
if let handlerToken = handlerToken {
54+
self.progressTupleHandlers.remove(handlerToken)
55+
}
5456
}
5557

56-
internal func addCompletionHandler(inout token: HandlerToken?, _ completionHandler: Void -> Void)
58+
internal func addCompletionHandler(inout token: _HandlerToken?, _ completionHandler: Void -> Void)
5759
{
5860
if self.state == .Running || self.state == .Paused {
5961
token = self.completionHandlers.append(completionHandler)
6062
}
6163
}
6264

63-
internal func removeCompletionHandler(handlerToken: HandlerToken)
65+
internal func removeCompletionHandler(handlerToken: _HandlerToken?)
6466
{
65-
self.completionHandlers.remove(handlerToken)
67+
if let handlerToken = handlerToken {
68+
self.completionHandlers.remove(handlerToken)
69+
}
6670
}
6771

6872
internal func handleProgress(progress: Progress)
@@ -201,7 +205,7 @@ internal class _StateMachine<Progress, Value, Error>
201205
// MARK: - Utility
202206
//--------------------------------------------------
203207

204-
public struct HandlerToken
208+
internal struct _HandlerToken
205209
{
206210
internal let key: Int
207211
}
@@ -211,16 +215,16 @@ internal struct _Handlers<T>: SequenceType
211215
private var currentKey: Int = 0
212216
private var elements = [Int : T]()
213217

214-
internal mutating func append(value: T) -> HandlerToken
218+
internal mutating func append(value: T) -> _HandlerToken
215219
{
216220
self.currentKey = self.currentKey &+ 1
217221

218222
self.elements[self.currentKey] = value
219223

220-
return HandlerToken(key: self.currentKey)
224+
return _HandlerToken(key: self.currentKey)
221225
}
222226

223-
internal mutating func remove(token: HandlerToken)
227+
internal mutating func remove(token: _HandlerToken)
224228
{
225229
self.elements.removeValueForKey(token.key)
226230
}

0 commit comments

Comments
 (0)