diff --git a/SwiftTask.xcodeproj/project.pbxproj b/SwiftTask.xcodeproj/project.pbxproj index 7afd54e..c6cc96e 100644 --- a/SwiftTask.xcodeproj/project.pbxproj +++ b/SwiftTask.xcodeproj/project.pbxproj @@ -306,9 +306,11 @@ TargetAttributes = { 1F46DED3199EDF1000F97868 = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0800; }; 1F46DEDE199EDF1000F97868 = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0800; }; 4822F0CF19D00ABF00F5F572 = { CreatedOnToolsVersion = 6.0.1; @@ -518,6 +520,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -537,6 +540,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 2.3; }; name = Release; }; @@ -554,6 +558,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -567,6 +572,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; + SWIFT_VERSION = 2.3; }; name = Release; }; @@ -583,6 +589,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -595,6 +602,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SWIFT_VERSION = 2.3; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/SwiftTask/SwiftTask.swift b/SwiftTask/SwiftTask.swift index 7fec21b..5008326 100644 --- a/SwiftTask/SwiftTask.swift +++ b/SwiftTask/SwiftTask.swift @@ -185,6 +185,14 @@ public class Task: Cancellable, CustomStringConvertible }) self.name = "RejectedTask" } + + private convenience init(_errorInfo: ErrorInfo) + { + self.init(_initClosure: { _, progress, fulfill, _reject, configure in + _reject(_errorInfo) + }) + self.name = "RejectedTask" + } /// /// Create promise-like task which only allows fulfill & reject (no progress & configure) @@ -310,18 +318,24 @@ public class Task: Cancellable, CustomStringConvertible clonedTask.name = "\(self.name)-clone" return clonedTask } - + /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. - public func retry(maxRetryCount: Int) -> Task + /// - Parameter condition: Predicate that will be evaluated on each retry timing. + public func retry(maxRetryCount: Int, condition: (ErrorInfo -> Bool) = { _ in true }) -> Task { - if maxRetryCount < 1 { return self } - + guard maxRetryCount > 0 else { return self } + return Task { machine, progress, fulfill, _reject, configure in let task = self.progress { _, progressValue in progress(progressValue) - }.failure { [unowned self] _ -> Task in - return self.clone().retry(maxRetryCount-1) // clone & try recursively + }.failure { [unowned self] errorInfo -> Task in + if condition(errorInfo) { + return self.clone().retry(maxRetryCount-1, condition: condition) // clone & try recursively + } + else { + return Task(_errorInfo: errorInfo) + } } task.progress { _, progressValue in diff --git a/SwiftTaskTests/SwiftTaskTests.swift b/SwiftTaskTests/SwiftTaskTests.swift index b7fedd6..f88e753 100644 --- a/SwiftTaskTests/SwiftTaskTests.swift +++ b/SwiftTaskTests/SwiftTaskTests.swift @@ -892,6 +892,41 @@ class SwiftTaskTests: _TestCase XCTAssertEqual(actualTryCount, maxTryCount, "`actualTryCount` should reach `maxTryCount` because task keeps rejected and never fulfilled.") } + func testRetry_condition() + { + // NOTE: this is async test + if !self.isAsync { return } + + let expect = self.expectationWithDescription(#function) + let maxTryCount = 4 + var actualTryCount = 0 + + Task { progress, fulfill, reject, configure in + + self.perform { + actualTryCount += 1 + reject("ERROR \(actualTryCount)") + } + + }.retry(maxTryCount-1) { error, isCancelled -> Bool in + XCTAssertNotEqual(error!, "ERROR 0", "Should not evaluate retry condition on first try. It is not retry.") + return actualTryCount < 3 + }.failure { error, isCancelled -> String in + + XCTAssertEqual(error!, "ERROR 3") + XCTAssertFalse(isCancelled) + + expect.fulfill() + + return "DUMMY" + + } + + self.wait() + + XCTAssertEqual(actualTryCount, 3) + } + func testRetry_progress() { // NOTE: this is async test