From 18cd62cfabd1a8078d0100fd5cdefca46bf0800a Mon Sep 17 00:00:00 2001 From: r-plus Date: Thu, 4 Aug 2016 11:30:30 +0900 Subject: [PATCH 1/6] Add retry(_:condition:) method. --- SwiftTask/SwiftTask.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/SwiftTask/SwiftTask.swift b/SwiftTask/SwiftTask.swift index 7fec21b..bfed5d3 100644 --- a/SwiftTask/SwiftTask.swift +++ b/SwiftTask/SwiftTask.swift @@ -313,15 +313,23 @@ public class Task: Cancellable, CustomStringConvertible /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. public func retry(maxRetryCount: Int) -> Task + { + return retry(maxRetryCount) { true } + } + + /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. + /// Predicated condition will evaluate when each retry timing to handle retryable. + public func retry(maxRetryCount: Int, condition predicate: () -> Bool) -> Task { if maxRetryCount < 1 { return self } + if !predicate() { 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 + return self.clone().retry(maxRetryCount-1, condition: predicate) // clone & try recursively } task.progress { _, progressValue in From d9761dfe8a153ed8dcec8fc044f6fc9dc009dda4 Mon Sep 17 00:00:00 2001 From: r-plus Date: Thu, 4 Aug 2016 12:17:36 +0900 Subject: [PATCH 2/6] Add conditional retry test. --- SwiftTaskTests/SwiftTaskTests.swift | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/SwiftTaskTests/SwiftTaskTests.swift b/SwiftTaskTests/SwiftTaskTests.swift index b7fedd6..ac79282 100644 --- a/SwiftTaskTests/SwiftTaskTests.swift +++ b/SwiftTaskTests/SwiftTaskTests.swift @@ -892,6 +892,40 @@ 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) { () -> Bool in + return actualTryCount < 2 + }.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 From 328c18280d5709ff90d97d38c3318b73ec4cdbd7 Mon Sep 17 00:00:00 2001 From: r-plus Date: Thu, 4 Aug 2016 22:46:45 +0900 Subject: [PATCH 3/6] Pass ErrorInfo to retry condition argument and do not evaluate condition on first try --- SwiftTask/SwiftTask.swift | 16 +++++++++++----- SwiftTaskTests/SwiftTaskTests.swift | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/SwiftTask/SwiftTask.swift b/SwiftTask/SwiftTask.swift index bfed5d3..b86386c 100644 --- a/SwiftTask/SwiftTask.swift +++ b/SwiftTask/SwiftTask.swift @@ -314,22 +314,28 @@ public class Task: Cancellable, CustomStringConvertible /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. public func retry(maxRetryCount: Int) -> Task { - return retry(maxRetryCount) { true } + return retry(maxRetryCount, errorInfo: nil) { _ in true } } /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. /// Predicated condition will evaluate when each retry timing to handle retryable. - public func retry(maxRetryCount: Int, condition predicate: () -> Bool) -> Task + public func retry(maxRetryCount: Int, condition predicate: ErrorInfo -> Bool) -> Task + { + return retry(maxRetryCount, errorInfo: nil, condition: predicate) + } + + private func retry(maxRetryCount: Int, errorInfo: ErrorInfo?, condition predicate: ErrorInfo -> Bool) -> Task { if maxRetryCount < 1 { return self } - if !predicate() { return self } + // Skip evaluation on first try. It is not retry. + if let errorInfo = errorInfo where !predicate(errorInfo) { 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, condition: predicate) // clone & try recursively + }.failure { [unowned self] errorInfo -> Task in + return self.clone().retry(maxRetryCount-1, errorInfo: errorInfo, condition: predicate) // clone & try recursively } task.progress { _, progressValue in diff --git a/SwiftTaskTests/SwiftTaskTests.swift b/SwiftTaskTests/SwiftTaskTests.swift index ac79282..4af3ec7 100644 --- a/SwiftTaskTests/SwiftTaskTests.swift +++ b/SwiftTaskTests/SwiftTaskTests.swift @@ -908,7 +908,8 @@ class SwiftTaskTests: _TestCase reject("ERROR \(actualTryCount)") } - }.retry(maxTryCount-1) { () -> Bool in + }.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 < 2 }.failure { error, isCancelled -> String in From 42b6e904ed15bb72d4a4bbf0945ff4f3bfbfb519 Mon Sep 17 00:00:00 2001 From: Yasuhiro Inami Date: Fri, 5 Aug 2016 00:08:46 +0900 Subject: [PATCH 4/6] Improve 328c182 --- SwiftTask/SwiftTask.swift | 38 ++++++++++++++--------------- SwiftTaskTests/SwiftTaskTests.swift | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/SwiftTask/SwiftTask.swift b/SwiftTask/SwiftTask.swift index b86386c..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,32 +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 - { - return retry(maxRetryCount, errorInfo: nil) { _ in true } - } - + /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. - /// Predicated condition will evaluate when each retry timing to handle retryable. - public func retry(maxRetryCount: Int, condition predicate: ErrorInfo -> Bool) -> Task + /// - Parameter condition: Predicate that will be evaluated on each retry timing. + public func retry(maxRetryCount: Int, condition: (ErrorInfo -> Bool) = { _ in true }) -> Task { - return retry(maxRetryCount, errorInfo: nil, condition: predicate) - } - - private func retry(maxRetryCount: Int, errorInfo: ErrorInfo?, condition predicate: ErrorInfo -> Bool) -> Task - { - if maxRetryCount < 1 { return self } - // Skip evaluation on first try. It is not retry. - if let errorInfo = errorInfo where !predicate(errorInfo) { 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] errorInfo -> Task in - return self.clone().retry(maxRetryCount-1, errorInfo: errorInfo, condition: predicate) // clone & try recursively + 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 4af3ec7..f88e753 100644 --- a/SwiftTaskTests/SwiftTaskTests.swift +++ b/SwiftTaskTests/SwiftTaskTests.swift @@ -910,7 +910,7 @@ class SwiftTaskTests: _TestCase }.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 < 2 + return actualTryCount < 3 }.failure { error, isCancelled -> String in XCTAssertEqual(error!, "ERROR 3") From e750ee5d7c088a65862326559344b22b25e79ec3 Mon Sep 17 00:00:00 2001 From: Yasuhiro Hatta Date: Sun, 25 Sep 2016 02:57:24 +0900 Subject: [PATCH 5/6] Update for Xcode 8 (with Swift 2.3) --- SwiftTask.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SwiftTask.xcodeproj/project.pbxproj b/SwiftTask.xcodeproj/project.pbxproj index 7afd54e..36d38d8 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; }; From 8fa471f7554279ccd3fadf45f64db12b4d48519c Mon Sep 17 00:00:00 2001 From: Yasuhiro Hatta Date: Sun, 25 Sep 2016 03:39:00 +0900 Subject: [PATCH 6/6] Set "Use Legacy Swift Language Version = Yes" for "SwiftTask-iOSTests" target --- SwiftTask.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SwiftTask.xcodeproj/project.pbxproj b/SwiftTask.xcodeproj/project.pbxproj index 36d38d8..c6cc96e 100644 --- a/SwiftTask.xcodeproj/project.pbxproj +++ b/SwiftTask.xcodeproj/project.pbxproj @@ -589,6 +589,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.inamiy.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -601,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;