From d1b4023796f8bab778f52a11eb058c070f00860d Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 14 Jul 2018 16:13:54 +0200 Subject: [PATCH 01/57] Adding support to Xcode 10 and Swift 4.2 --- .swift-version | 2 +- CHANGELOG.md | 6 ++++++ Queuer.podspec | 2 +- Queuer.xcodeproj/project.pbxproj | 6 ++++-- Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme | 6 ++---- .../xcshareddata/xcschemes/Queuer macOS.xcscheme | 6 ++---- .../xcshareddata/xcschemes/Queuer tvOS.xcscheme | 6 ++---- .../xcshareddata/xcschemes/Queuer watchOS.xcscheme | 6 ++---- README.md | 1 + 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.swift-version b/.swift-version index 7d5c902..bf77d54 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.1 +4.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 67ba6ae..ced3328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ All notable changes to this project will be documented in this file.
--- +## Swift 4.2 +### Added +- Added support to Xcode 10 and Swift 4.2 + +--- + ## Develop ### Removed - Removed Hound CI diff --git a/Queuer.podspec b/Queuer.podspec index 4477a21..d9eefa3 100644 --- a/Queuer.podspec +++ b/Queuer.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/FabrizioBrancati/Queuer.git', :tag => s.version } s.documentation_url = 'https://github.fabriziobrancati.com/documentation/Queuer/' - s.swift_version = '4.1' + s.swift_version = '4.2' s.source_files = 'Sources/**/*.swift' diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index 618e7f1..1975dd6 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -728,6 +728,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -784,7 +785,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -809,6 +810,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -857,7 +859,7 @@ PRODUCT_NAME = Queuer; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme index 5a9199e..be2f8d0 100644 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme +++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme @@ -26,9 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -57,7 +56,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme index f32be8e..394e377 100644 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme +++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme @@ -26,9 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -57,7 +56,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme index 2cdf53b..a0fc727 100644 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme +++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme @@ -26,9 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -57,7 +56,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme index 0624fe0..485d9c2 100644 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme +++ b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme @@ -26,9 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -38,7 +37,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/README.md b/README.md index c0bc462..bfff7b2 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Requirements | 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | | 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | | 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | +| 4.2 | 10.0 | 1.x.x | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | > `*` Currently, `URLSession.shared` property is not yet implemented on Linux. From 363bac4149c2579f1d69653ee11f9e1f405fa682 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 4 Aug 2018 12:49:59 +0200 Subject: [PATCH 02/57] Minor changes to project --- Queuer.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index 1975dd6..ce71b7f 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -757,7 +757,6 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -781,9 +780,9 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=100 -Xfrontend -warn-long-function-bodies=100"; PRODUCT_NAME = Queuer; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; @@ -856,8 +855,9 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=100 -Xfrontend -warn-long-function-bodies=100"; PRODUCT_NAME = Queuer; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; From 2195c647822f419147ef831b54c0dfcf7964bbdf Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 25 Aug 2018 19:27:43 +0200 Subject: [PATCH 03/57] Updating to Xcode 10 --- .travis.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 78ed9a2..92bd072 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,23 +14,23 @@ matrix: env: SPM="YES" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: SPM="YES" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="YES" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.1,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.3.1,name=iPhone 6" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c @@ -38,31 +38,31 @@ matrix: env: PROJ="Queuer.xcodeproj" DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.2,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=2.0,name=Apple Watch - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO" - os: osx language: objective-c - osx_image: xcode9.4 + osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="arch=x86_64" SCHEME="$MACOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" before_install: From 8c542f83b47fc2604b8d3e3e787240308bf55c4a Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 25 Aug 2018 19:46:11 +0200 Subject: [PATCH 04/57] Updating to iOS 12 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92bd072..8a6dd99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,11 +19,11 @@ matrix: - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="YES" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=12.0,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="YES" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.1,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" CODECOV="NO" - os: osx language: objective-c osx_image: xcode10 From 3380fbd79b44afde1b0f85e61df09365f579e725 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 25 Aug 2018 19:46:20 +0200 Subject: [PATCH 05/57] Minor change --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8a6dd99..4f1bff7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ matrix: - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" - os: osx language: objective-c osx_image: xcode9.2 From 31456ce3dd80154afdbc0b9f302b3659342b1ff3 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 26 Aug 2018 12:36:09 +0200 Subject: [PATCH 06/57] Fixing tests --- Tests/QueuerTests/RequestOperationTests.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Tests/QueuerTests/RequestOperationTests.swift b/Tests/QueuerTests/RequestOperationTests.swift index b0f5422..7837137 100644 --- a/Tests/QueuerTests/RequestOperationTests.swift +++ b/Tests/QueuerTests/RequestOperationTests.swift @@ -73,8 +73,11 @@ internal class RequestOperationTests: XCTestCase { requestOperation.addToQueue(queue) XCTAssertEqual(requestOperation.url?.absoluteString, self.testAddress) - XCTAssertEqual(requestOperation.query, "?test=test&test2=test2") - XCTAssertEqual(requestOperation.completeURL, URL(string: self.testAddress + "?test=test&test2=test2")) + XCTAssertTrue(requestOperation.query?.contains("test=test") ?? false) + XCTAssertTrue(requestOperation.query?.contains("test2=test2") ?? false) + XCTAssertTrue(requestOperation.completeURL?.absoluteString.contains(self.testAddress) ?? false) + XCTAssertTrue(requestOperation.completeURL?.absoluteString.contains("test=test") ?? false) + XCTAssertTrue(requestOperation.completeURL?.absoluteString.contains("test2=test2") ?? false) XCTAssertEqual(requestOperation.timeout, 30) XCTAssertEqual(requestOperation.method, .get) XCTAssertEqual(requestOperation.headers ?? [:], ["test": "test", "test2": "test2"]) From 5395910de7deb8e90ecc649fa1209f46d102ae21 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 27 Aug 2018 00:14:28 +0200 Subject: [PATCH 07/57] Updating Swiftenv --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f1bff7..93cc90d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,7 @@ before_install: install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/02090c7ede5a637b76e6df1710e83cd0bbe7dcdf/swiftenv-install.sh)"; + eval "$(curl -sL https://swiftenv.fuller.li/install.sh)"; fi - if [ "$TRAVIS_OS_NAME" == "osx" ]; then ./install_swiftlint.sh; From 611ec1c4d7b076f3885f0ba5490718f5a446311d Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 27 Aug 2018 00:30:15 +0200 Subject: [PATCH 08/57] Using to Coveralls --- .travis.yml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 93cc90d..689bbc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,51 +19,51 @@ matrix: - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=12.0,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="YES" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=12.0,name=iPhone X" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="YES" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.4,name=iPhone 7 Plus" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="YES" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.3.1,name=iPhone 6" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.3.1,name=iPhone 6" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=iPhone 5s" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode9.2 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.2,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=11.2,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=2.0,name=Apple Watch - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=2.0,name=Apple Watch - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="arch=x86_64" SCHEME="$MACOS_SCHEME" RUN_TESTS="YES" LINT="NO" CODECOV="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="arch=x86_64" SCHEME="$MACOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" before_install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then @@ -71,6 +71,7 @@ before_install: gem install cocoapods --pre --no-rdoc --no-ri --no-document; brew update; brew outdated carthage || brew upgrade carthage; + gem install slather; fi install: @@ -110,6 +111,6 @@ script: fi after_success: - - if [ "$CODECOV" == "YES" ]; then - bash <(curl -s https://codecov.io/bash) -X xcodeplist; + - if [ "$COVERAGE" == "YES" ]; then + slather; fi From b77a72afde76dd0b24697526a0d2b11f55c67110 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Tue, 28 Aug 2018 00:03:57 +0200 Subject: [PATCH 09/57] Adding Slather file --- .slather.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .slather.yml diff --git a/.slather.yml b/.slather.yml new file mode 100644 index 0000000..4cf7de0 --- /dev/null +++ b/.slather.yml @@ -0,0 +1,5 @@ +coverage_service: coveralls +xcodeproj: Queuer.xcodeproj +scheme: Queuer iOS +ignore: + - Tests/* From eabe8e57de9375efbde89925ed1e349f7c348f70 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Wed, 29 Aug 2018 01:32:54 +0200 Subject: [PATCH 10/57] Moving to Coveralls --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93370c6..5aabf3a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

[![Build Status](https://travis-ci.org/FabrizioBrancati/Queuer.svg?branch=master)](https://travis-ci.org/FabrizioBrancati/Queuer) -[![Codecov](https://codecov.io/gh/FabrizioBrancati/Queuer/branch/master/graph/badge.svg)](https://codecov.io/gh/FabrizioBrancati/Queuer) +[![Coverage Status](https://coveralls.io/repos/github/FabrizioBrancati/Queuer/badge.svg?branch=master)](https://coveralls.io/github/FabrizioBrancati/Queuer?branch=master) [![Documentation](https://github.fabriziobrancati.com/documentation/Queuer/badge.svg)](https://github.fabriziobrancati.com/documentation/Queuer/) [![codebeat badge](https://codebeat.co/badges/50844e60-f4f2-4f9f-a688-5ccc976b7c8c)](https://codebeat.co/projects/github-com-fabriziobrancati-queuer-master-9833cda0-af64-433d-a08a-cd0d50d6b579) [![Swift Package Manager Compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) From 0cb58902e0bcf8184da95e233e6b296560344119 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 9 Sep 2018 23:48:20 +0200 Subject: [PATCH 11/57] Updating changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b209d..20e370f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ All notable changes to this project will be documented in this file.
### Added - Added support to Xcode 10 and Swift 4.2 +### Changed +- Changed from Codecov to Coveralls service for code coverage + --- ## Develop From 00e2bdba19a267fb0bb3ee1febf0654dcff3d884 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Tue, 11 Sep 2018 01:41:54 +0200 Subject: [PATCH 12/57] Removing Codecov file --- .codecov.yml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .codecov.yml diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index cd68870..0000000 --- a/.codecov.yml +++ /dev/null @@ -1,6 +0,0 @@ -coverage: - status: - patch: on - -ignore: - - Tests/**/* From 60835be4adeb4654aad8925e01cf3a9d62ab6257 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:03:39 +0200 Subject: [PATCH 13/57] Updated package tools version to 4.2 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index c14ec86..5cd57f1 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.0 +// swift-tools-version:4.2 // // Package.swift // Queuer From 1a5632a7f7f2195a968c1d3b28619895f96cde56 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:04:50 +0200 Subject: [PATCH 14/57] Removing RequestOperation class --- Queuer.xcodeproj/project.pbxproj | 18 -- README.md | 41 +--- Sources/Queuer/RequestOperation.swift | 230 ------------------ Tests/QueuerTests/RequestOperationTests.swift | 203 ---------------- 4 files changed, 3 insertions(+), 489 deletions(-) delete mode 100644 Sources/Queuer/RequestOperation.swift delete mode 100644 Tests/QueuerTests/RequestOperationTests.swift diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index ce71b7f..a348365 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -15,47 +15,33 @@ 49B28E2E1F27EDCC00D0819A /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 49C7BCCE1F26938F00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; }; 49C7BCCF1F26938F00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; }; - 49C7BCD01F26938F00F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; }; 49C7BCD11F26938F00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; 49C7BCD21F26938F00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCD31F26938F00F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; }; 49C7BCD41F26938F00F4FFBC /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 49C7BCD51F26939900F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; }; 49C7BCD61F26939900F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; }; - 49C7BCD71F26939900F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; }; 49C7BCD81F26939900F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; 49C7BCD91F26939900F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCDA1F26939900F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; }; 49C7BCDB1F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; }; 49C7BCDC1F26939A00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; }; - 49C7BCDD1F26939A00F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; }; 49C7BCDE1F26939A00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; 49C7BCDF1F26939A00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCE01F26939A00F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; }; 49C7BCE11F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; }; 49C7BCE21F26939A00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; }; - 49C7BCE31F26939A00F4FFBC /* RequestOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */; }; 49C7BCE41F26939A00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; 49C7BCE51F26939A00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCE61F26939A00F4FFBC /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */; }; 49C7BCE71F26939F00F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; }; 49C7BCE81F26939F00F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; }; - 49C7BCE91F26939F00F4FFBC /* RequestOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */; }; 49C7BCEA1F26939F00F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; }; 49C7BCEB1F26939F00F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; }; - 49C7BCEC1F26939F00F4FFBC /* URLBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */; }; 49C7BCED1F2693A000F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; }; 49C7BCEE1F2693A000F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; }; - 49C7BCEF1F2693A000F4FFBC /* RequestOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */; }; 49C7BCF01F2693A000F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; }; 49C7BCF11F2693A000F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; }; - 49C7BCF21F2693A000F4FFBC /* URLBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */; }; 49C7BCF31F2693A100F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; }; 49C7BCF41F2693A100F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; }; - 49C7BCF51F2693A100F4FFBC /* RequestOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */; }; 49C7BCF61F2693A100F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; }; 49C7BCF71F2693A100F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; }; - 49C7BCF81F2693A100F4FFBC /* URLBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -93,20 +79,16 @@ 49C7BCAC1F26938F00F4FFBC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentOperationTests.swift; sourceTree = ""; }; 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueuerTests.swift; sourceTree = ""; }; - 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestOperationTests.swift; sourceTree = ""; }; 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemaphoreTests.swift; sourceTree = ""; }; 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousOperationTests.swift; sourceTree = ""; }; - 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLBuilderTests.swift; sourceTree = ""; }; 49C7BCB61F26938F00F4FFBC /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 49C7BCB71F26938F00F4FFBC /* Info-macOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; 49C7BCB81F26938F00F4FFBC /* Info-tvOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 49C7BCB91F26938F00F4FFBC /* Info-watchOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-watchOS.plist"; sourceTree = ""; }; 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentOperation.swift; sourceTree = ""; }; 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queuer.swift; sourceTree = ""; }; - 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestOperation.swift; sourceTree = ""; }; 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Semaphore.swift; sourceTree = ""; }; 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousOperation.swift; sourceTree = ""; }; - 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLBuilder.swift; sourceTree = ""; }; 49C7BCC11F26938F00F4FFBC /* Queuer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Queuer.h; sourceTree = ""; }; /* End PBXFileReference section */ diff --git a/README.md b/README.md index 5aabf3a..b23d3a8 100644 --- a/README.md +++ b/README.md @@ -226,13 +226,13 @@ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { queue.pause() ``` > By calling `pause()` you will not be sure that every operation will be paused. - If the Operation is already started it will not be on pause until it's a custom Operation that overrides `pause()` function or is a `RequestOperation`. + If the Operation is already started it will not be on pause until it's a custom Operation that overrides `pause()` function. - Resume queue: ```swift queue.resume() ``` - > To have a complete `pause` and `resume` states you must create a custom Operation that overrides `pause()` and `resume()` function or use a `RequestOperation`. + > To have a complete `pause` and `resume` states you must create a custom Operation that overrides `pause()` and `resume()` function. - Wait until all operations are finished: ```swift @@ -245,8 +245,7 @@ queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { It allows synchronous and asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block. You can create your custom `ConcurrentOperation` by subclassing it.
-You must override `execute()` function and call the `finish()` function inside it, when the task has finished its job to notify the queue.
-Look at [RequestOperation.swift](https://github.com/FabrizioBrancati/Queuer/blob/master/Sources/Queuer/RequestOperation.swift) if you are looking for an example. +You must override `execute()` function and call the `finish()` function inside it, when the task has finished its job to notify the queue. For convenience it has an `init` function with a completion block: ```swift @@ -294,40 +293,6 @@ concurrentOperation.addToQueue(queue) semaphore.wait() ``` -### Request Operation `*` -`RequestOperation` allows you to easily create a network request and add it to a queue: -```swift -let requestOperation: RequestOperation = RequestOperation(url: self.testAddress) { success, response, data, error in - -} -requestOperation.addToQueue(queue) -``` -Allowed parameters in `RequestOperation` `init` function: -- `url` is a `String` representing the request URL -- `query` is `Dictionary` representing the request query parameters to be added to the `url` with `?` and `&` characters -- `timeout` is the request timeout -- `method` is the request method, you can choose to one of: `connect`, `delete`, `get`, `head`, `options`, `patch`, `post` and `put` -- `cachePolicy` is the request cache policy, referrer to [CachePolicy documentation](https://developer.apple.com/documentation/foundation/nsurlrequest.cachepolicy) -- `headers` is a `Dictionary` representing the request headers -- `body` is a `Data` representing the request body -- `completionHandler` is the request response handler - -Response handler variables: -- `success` is a `Bool` indicating if the request was successful. - It's successful if its status is between 200 and 399, it wasn't cancelled and did't get any other network error. -- `respose` is an `HTTPURLResponse` instance. - It contains all the response headers and the status code. - May be `nil`. -- `data` is a `Data` instance with the request body. - You must convert, to a JSON or String in example, it in order to use. - May be `nil`. -- `error` is an `Error` instance with the request error. - May be `nil`. - -It can be `pause`d, `resume`d, `cancel`led and chained with other `Operation`s. - -> `*` Currently, `URLSession.shared` property is not yet implemented on Linux, also `RequestOperation` is currently deprecated and will be removed in Queuer 2. - Documentation ============= diff --git a/Sources/Queuer/RequestOperation.swift b/Sources/Queuer/RequestOperation.swift deleted file mode 100644 index 3fc7c40..0000000 --- a/Sources/Queuer/RequestOperation.swift +++ /dev/null @@ -1,230 +0,0 @@ -// -// RequestOperation.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2018 Fabrizio Brancati -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#if !os(Linux) - -import Foundation - -/// HTTP Method enum. -public enum HTTPMethod: String { - /// CONNECT method. - case connect = "CONNECT" - /// DELETE method. - case delete = "DELETE" - /// GET method. - case get = "GET" - /// HEAD method. - case head = "HEAD" - /// OPTIONS method. - case options = "OPTIONS" - /// PATCH method. - case patch = "PATCH" - /// POST method. - case post = "POST" - /// PUT method. - case put = "PUT" -} - -/// RequestOperation helps you to create network operation with an easy interface. -@available(*, deprecated: 1.3.2, message: "`RequestOperation` is deprecated and will be removed in Queuer 2.") -open class RequestOperation: ConcurrentOperation { - /// Custom HTTP errors. - public enum RequestError: Error { - /// URL doesn't exist. - case urlError - /// Operation has been cancelled. - case operationCancelled - } - - /// Request closure alias. - public typealias RequestClosure = (Bool, HTTPURLResponse?, Data?, Error?) -> Void - - /// Global cache policy for all request. - /// Also cache policy can be set per request. - public static var globalCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy - - /// Request task. - public private(set) var task: URLSessionDataTask? - /// Request URL. - public private(set) var url: URL? - /// Request query. - public private(set) var query: String? - /// Request complete URL - public private(set) var completeURL: URL? - /// Request timeout. - public private(set) var timeout: TimeInterval = 30 - /// Request HTTP method. - public private(set) var method: HTTPMethod = .get - /// Request cache policy. - public private(set) var cachePolicy: URLRequest.CachePolicy = globalCachePolicy - /// Request headers. - public private(set) var headers: [String: String]? - /// Request body. - public private(set) var body: Data? - /// Request completionHandler. - public private(set) var completionHandler: RequestClosure? - - /// URLSession instance. - open var session: URLSession { - let configuration = URLSessionConfiguration.default - if #available(iOS 11, macOS 10.13, tvOS 11, watchOS 4, *) { - configuration.waitsForConnectivity = true - } - return URLSession(configuration: configuration) - } - - /// URLRequest instance. - private var request: URLRequest! // swiftlint:disable:this implicitly_unwrapped_optional - - /// Private init with executrion block. - /// You can't create a RequestOperation with only an execution block. - /// - /// - Parameter block: Execution block. - override internal init(executionBlock: (() -> Void)? = nil) { - super.init(executionBlock: nil) - } - - /// Creates a RequestOperation, ready to be added in a queue. - /// - /// - Parameters: - /// - url: Request URL String. - /// - query: Request query. Default is nil. - /// - timeout: Request timeout. Default is 30 seconds. - /// - method: Request HTTP method. Default is `.get`. - /// - cachePolicy: Request cache policy. Use static var `globalCachePolicy` - /// to set a global cache policy for all the RequestOperations. - /// - headers: Request headers. Defatult is nil. - /// - body: Request body. Default is nil. - /// - completionHandler: Request completion handler. Default is nil. - public init(url: String, query: [String: String]? = nil, timeout: TimeInterval = 30, method: HTTPMethod = .get, cachePolicy: URLRequest.CachePolicy = globalCachePolicy, headers: [String: String]? = nil, body: Data? = nil, completionHandler: RequestClosure? = nil) { - super.init() - - let query = URLBuilder.build(query: query) - - self.query = query - self.url = URL(string: url) - self.completeURL = URL(string: url + query) - self.timeout = timeout - self.method = method - self.cachePolicy = cachePolicy - self.headers = headers - self.body = body - self.completionHandler = completionHandler - } - - /// Executes the request operation asynchronously. - override open func execute() { - /// Check if the Operation has been cancelled. - guard !self.isCancelled else { - if let completionHandler = completionHandler { - completionHandler(false, nil, nil, RequestError.operationCancelled) - } - - /// Notify that the Operation has finished execution. - self.finish() - - return - } - - /// Check if the URL can be used. - guard let url = self.completeURL else { - if let completionHandler = completionHandler { - completionHandler(false, nil, nil, RequestError.urlError) - } - - /// Notify that the Operation has finished execution. - finish() - - return - } - - /// Creates the request. - request = URLRequest(url: url, cachePolicy: self.cachePolicy, timeoutInterval: self.timeout) - /// Set the HTTP method. - request.httpMethod = method.rawValue - /// Set the HTTP body. - if let body = body { - request.httpBody = body - } - /// Set all the HTTP headers. - if let headers = headers { - headers.forEach { request.addValue($1, forHTTPHeaderField: $0) } - } - - /// Create the task. - task = session.dataTask(with: request) { [weak self] data, response, error in - /// Check if the Operation has a completion handler, has an HTTP response - /// and has not been canceled. - if let strongSelf = self { - if let completionHandler = strongSelf.completionHandler { - if let httpResponse = response as? HTTPURLResponse { - var error: Error? = error - /// Set `success` to true if the HTTP status code - /// is greater or equal than 200 and less than 400 - /// and has not been cancelled. - let success: Bool = httpResponse.statusCode >= 200 && httpResponse.statusCode < 400 && !strongSelf.isCancelled - - /// Check again if the request has not been cancelled. - if strongSelf.isCancelled { - error = RequestError.operationCancelled - } - - completionHandler(success, httpResponse, data, error) - } else { - completionHandler(false, nil, data, error) - } - } - /// Notify that the Operation has finished execution. - strongSelf.finish() - } - } - /// Start the task. - task?.resume() - } - - /// Cancels the request operation. - override open func cancel() { - super.cancel() - - task?.cancel() - } - - /// Suspends the request operation. - override open func pause() { - super.pause() - - task?.suspend() - } - - /// Resumes the request operation. - override open func resume() { - super.resume() - - task?.resume() - } -} - -#endif diff --git a/Tests/QueuerTests/RequestOperationTests.swift b/Tests/QueuerTests/RequestOperationTests.swift deleted file mode 100644 index 7837137..0000000 --- a/Tests/QueuerTests/RequestOperationTests.swift +++ /dev/null @@ -1,203 +0,0 @@ -// -// RequestOperationTests.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2018 Fabrizio Brancati -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#if !os(Linux) - -@testable import Queuer -import XCTest - -internal class RequestOperationTests: XCTestCase { - internal static let allTests = [ - ("testInitFull", testInitFull), - ("testExecute", testExecute), - ("testUnsupportedURL", testUnsupportedURL), - ("testWrongURL", testWrongURL), - ("testWithoutCompletionHandler", testWithoutCompletionHandler), - ("testCancel", testCancel), - ("testPauseAndResume", testPauseAndResume) - ] - - internal let testAddress: String = "https://google.com" - - override internal func setUp() { - super.setUp() - - RequestOperation.globalCachePolicy = .reloadIgnoringLocalCacheData - } - - internal func testInit() { - let queue = Queuer(name: "RequestOperationTestInit") - - let requestOperation = RequestOperation() - requestOperation.addToQueue(queue) - - XCTAssertNil(requestOperation.url?.absoluteString) - XCTAssertNil(requestOperation.query) - XCTAssertNil(requestOperation.completeURL) - XCTAssertEqual(requestOperation.timeout, 30) - XCTAssertEqual(requestOperation.method, .get) - XCTAssertEqual(requestOperation.headers ?? [:], [:]) - XCTAssertNil(requestOperation.body) - } - - internal func testInitFull() { - let queue = Queuer(name: "RequestOperationTestInitFull") - let testExpectation = expectation(description: "InitFull") - - let requestOperation = RequestOperation(url: self.testAddress, query: ["test": "test", "test2": "test2"], timeout: 30, method: .get, headers: ["test": "test", "test2": "test2"], body: Data()) { _, _, _, _ in - testExpectation.fulfill() - } - requestOperation.addToQueue(queue) - - XCTAssertEqual(requestOperation.url?.absoluteString, self.testAddress) - XCTAssertTrue(requestOperation.query?.contains("test=test") ?? false) - XCTAssertTrue(requestOperation.query?.contains("test2=test2") ?? false) - XCTAssertTrue(requestOperation.completeURL?.absoluteString.contains(self.testAddress) ?? false) - XCTAssertTrue(requestOperation.completeURL?.absoluteString.contains("test=test") ?? false) - XCTAssertTrue(requestOperation.completeURL?.absoluteString.contains("test2=test2") ?? false) - XCTAssertEqual(requestOperation.timeout, 30) - XCTAssertEqual(requestOperation.method, .get) - XCTAssertEqual(requestOperation.headers ?? [:], ["test": "test", "test2": "test2"]) - XCTAssertEqual(requestOperation.body, Data()) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - } - } - - internal func testExecute() { - let queue = Queuer(name: "RequestOperationTestExecute") - let testExpectation = expectation(description: "Execute") - - let requestOperation = RequestOperation(url: self.testAddress) { success, _, _, error in - XCTAssertNil(error) - XCTAssertTrue(success) - testExpectation.fulfill() - } - requestOperation.addToQueue(queue) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - } - } - - internal func testUnsupportedURL() { - let queue = Queuer(name: "RequestOperationTestUnsupportedURL") - let testExpectation = expectation(description: "Unsupported URL") - - let requestOperation = RequestOperation(url: "/path/to/something") { success, _, _, error in - XCTAssertTrue(error is URLError) - XCTAssertFalse(success) - testExpectation.fulfill() - } - requestOperation.addToQueue(queue) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - } - } - - internal func testWrongURL() { - let queue = Queuer(name: "RequestOperationTestWrongURL") - let testExpectation = expectation(description: "Wrong URL") - - let requestOperation = RequestOperation(url: "👍") { success, _, _, error in - XCTAssertEqual(error as? RequestOperation.RequestError, RequestOperation.RequestError.urlError) - XCTAssertFalse(success) - testExpectation.fulfill() - } - requestOperation.addToQueue(queue) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - } - } - - internal func testWithoutCompletionHandler() { - let queue = Queuer(name: "RequestOperationTestWithoutCompletionHandler") - let requestOperation = RequestOperation(url: self.testAddress) - requestOperation.addToQueue(queue) - - XCTAssertEqual(queue.operations, [requestOperation]) - XCTAssertEqual(queue.operationCount, 1) - } - - internal func testCancel() { - let queue = Queuer(name: "RequestOperationTestCancel") - let testExpectation = expectation(description: "Cancel") - - let requestOperation = RequestOperation(url: "http://fakehttpaddress.com/", cachePolicy: .reloadIgnoringLocalCacheData) { success, _, _, _ in - // Currently there is no easy way to check in time if the operation was cancelled before completion. - // XCTAssertEqual(error as? RequestOperation.RequestError, RequestOperation.RequestError.operationCancelled) - XCTAssertFalse(success) - testExpectation.fulfill() - } - requestOperation.addToQueue(queue) - - requestOperation.cancel() - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - } - } - - internal func testPauseAndResume() { - let queue = Queuer(name: "RequestOperationTestPauseAndResume") - let testExpectation = expectation(description: "Pause and Resume") - var order: [Int] = [] - - let requestOperation1 = RequestOperation(url: self.testAddress) { success, _, _, error in - XCTAssertNil(error) - XCTAssertTrue(success) - order.append(0) - } - let requestOperation2 = RequestOperation(url: self.testAddress) { success, _, _, error in - XCTAssertNil(error) - XCTAssertTrue(success) - order.append(1) - } - queue.addChainedOperations([requestOperation1, requestOperation2]) { - order.append(2) - } - - queue.pause() - testExpectation.fulfill() - - XCTAssertLessThanOrEqual(queue.operationCount, 3) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - XCTAssertFalse(queue.isExecuting) - XCTAssertLessThanOrEqual(queue.operationCount, 3) - XCTAssertNotEqual(order, [0, 1, 2]) - - queue.resume() - XCTAssertTrue(queue.isExecuting) - } - } -} - -#endif From 37df161711b235b3eaece652fc66925338c6d853 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:05:05 +0200 Subject: [PATCH 15/57] Removing URLBuilder --- Sources/Queuer/URLBuilder.swift | 50 ----------------- Tests/QueuerTests/URLBuilderTests.swift | 73 ------------------------- 2 files changed, 123 deletions(-) delete mode 100644 Sources/Queuer/URLBuilder.swift delete mode 100644 Tests/QueuerTests/URLBuilderTests.swift diff --git a/Sources/Queuer/URLBuilder.swift b/Sources/Queuer/URLBuilder.swift deleted file mode 100644 index c139701..0000000 --- a/Sources/Queuer/URLBuilder.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// URLBuilder.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2018 Fabrizio Brancati -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import Foundation - -/// URL builder struct. -internal enum URLBuilder { - /// Builds the query as a string, ready to be added in the URL. - /// - /// - Parameter query: Query dictionary. - /// - Returns: Returns the query as a String. - internal static func build(query: [String: String]?) -> String { - guard let query = query else { - return "" - } - - var finalQuery: String = "" - for (index, parameter) in query.enumerated() { - guard let parameterKey = parameter.key.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed), let parameterValue = parameter.value.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else { - continue - } - finalQuery += index == 0 ? "?" : "&" - finalQuery += parameterKey + "=" + parameterValue - } - return finalQuery - } -} diff --git a/Tests/QueuerTests/URLBuilderTests.swift b/Tests/QueuerTests/URLBuilderTests.swift deleted file mode 100644 index d730d6d..0000000 --- a/Tests/QueuerTests/URLBuilderTests.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// URLBuilderTests.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2018 Fabrizio Brancati -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -@testable import Queuer -import XCTest - -internal class URLBuilderTests: XCTestCase { - internal static let allTests = [ - ("testWithoutParameters", testWithoutParameters), - ("testWithSingleParameter", testBuildURLWithSingleParameter), - ("testWithMultipleParameters", testWithMultipleParameters), - ("testWithEmojiCharctersInParameters", testWithEmojiCharctersInParameters) - //("testWithStrangeCharctersInParameters", testWithStrangeCharctersInParameters) - ] - - internal func testWithoutParameters() { - let query = URLBuilder.build(query: [:]) - - XCTAssertEqual(query, "") - } - - internal func testBuildURLWithSingleParameter() { - let query = URLBuilder.build(query: ["test": "test"]) - - XCTAssertEqual(query, "?test=test") - } - - internal func testWithMultipleParameters() { - let query = URLBuilder.build(query: ["test": "test", "test2": "test2"]) - - XCTAssert(query == "?test=test&test2=test2" || query == "?test2=test2&test=test") - } - - internal func testWithEmojiCharctersInParameters() { - let query = URLBuilder.build(query: ["test": "test", "test👍": "test👍"]) - - XCTAssert(query == "?test=test&test%F0%9F%91%8D=test%F0%9F%91%8D" || query == "?test%F0%9F%91%8D=test%F0%9F%91%8D&test=test") - } - - /// Thanks to [Stack Overflow](https://stackoverflow.com/a/33558934/4032046 ). - internal func testWithStrangeCharctersInParameters() { - guard let string = String(bytes: [0xD8, 0x00] as [UInt8], encoding: String.Encoding.utf16BigEndian) else { - XCTFail("`testWithStrangeCharctersInParameters` error") - return - } - - let query = URLBuilder.build(query: [string: "test", "test👍": string]) - XCTAssertEqual(query, "") - } -} From 577115246618387ce4f53c97cfc338868342f5ce Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:05:26 +0200 Subject: [PATCH 16/57] Allowing custom timeout on Semaphore --- Sources/Queuer/Semaphore.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Queuer/Semaphore.swift b/Sources/Queuer/Semaphore.swift index a31987c..17722f5 100644 --- a/Sources/Queuer/Semaphore.swift +++ b/Sources/Queuer/Semaphore.swift @@ -46,8 +46,8 @@ public struct Semaphore { /// Wait for a `continue` function call. @discardableResult - public func wait() -> DispatchTimeoutResult { - return semaphore.wait(timeout: .distantFuture) + public func wait(_ timeout: DispatchTime = .distantFuture) -> DispatchTimeoutResult { + return semaphore.wait(timeout: timeout) } /// This function returns non-zero if a thread is woken. Otherwise, zero is returned. From 7447d0d9a0dba665c9ebe0939104baec95b2a095 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:05:34 +0200 Subject: [PATCH 17/57] Minor changes --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b23d3a8..24baef3 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,12 @@ Here is the list of all the features: Requirements ============ -| **Swift** | **Xcode** | **Queuer** | **iOS** | **macOS** | **tvOS** | **watchOS** | **Linux** | -|-----------|-----------|---------------|---------|-----------|----------|-------------|-----------| -| 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | -| 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | -| 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | -| 4.2 | 10.0 | 1.x.x | 8.0+ | 10.10 | 9.0 | 2.0+ | ![✓] `*` | +| **Swift** | **Xcode** | **Queuer** | **iOS** | **macOS** | **tvOS** | **watchOS** | **Linux** | +|-----------|-----------|---------------|---------|------------|-----------|-------------|-----------| +| 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | +| 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | +| 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | +| 4.2 | 10.0 | 2.x.x | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | > `*` Currently, `URLSession.shared` property is not yet implemented on Linux. @@ -132,7 +132,7 @@ See [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) sect - Create a **Package.swift** file in your **project directory** and write into: ```swift - // swift-tools-version:4.0 + // swift-tools-version:4.2 import PackageDescription let package = Package( From 35ea8175327c26043aa3f5f19fe1724399bb7626 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:05:47 +0200 Subject: [PATCH 18/57] Fixing Linux tests --- Tests/LinuxMain.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index fd29c7b..c1defa8 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -31,7 +31,6 @@ import XCTest XCTMain([ testCase(ConcurrentOperationTests.allTests), testCase(QueuerTests.allTests), - testCase(URLBuilderTests.allTests), testCase(SemaphoreTests.allTests), testCase(SynchronousOperationTests.allTests) ]) From 70ec90e598ba099f978046312c2622459c25b880 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:10:25 +0200 Subject: [PATCH 19/57] Improving README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 24baef3..c718e7e 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,11 @@ defer { semaphore.continue() } /// Your task here ``` +You can even set a custom timeout, default is `.distantFuture`: +```swift +semaphore.wait(DispatchTime(uptimeNanoseconds: 1_000_000_000)) +``` + It's more useful if used inside an asynchronous task: ```swift let concurrentOperation = ConcurrentOperation { From 565ad5fa2881793e9ab1fec7b99a8393061dac62 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:10:47 +0200 Subject: [PATCH 20/57] Adding Scheduler struct --- Queuer.xcodeproj/project.pbxproj | 36 +++++++-------- Sources/Queuer/Scheduler.swift | 61 +++++++++++++++++++++++++ Tests/LinuxMain.swift | 1 + Tests/QueuerTests/SchedulerTests.swift | 63 ++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 18 deletions(-) create mode 100644 Sources/Queuer/Scheduler.swift create mode 100644 Tests/QueuerTests/SchedulerTests.swift diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index a348365..fdac045 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -8,6 +8,13 @@ /* Begin PBXBuildFile section */ 493F57291F21F32B009EC8FA /* Queuer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 493F57201F21F32B009EC8FA /* Queuer.framework */; }; + 4946BDF6214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; }; + 4946BDF7214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; }; + 4946BDF8214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; }; + 4946BDF9214D586900FAFC84 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDF5214D586900FAFC84 /* Scheduler.swift */; }; + 4946BDFB214D5C0100FAFC84 /* SchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */; }; + 4946BDFC214D5C0100FAFC84 /* SchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */; }; + 4946BDFD214D5C0100FAFC84 /* SchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */; }; 4995D7431F21E19C00A34E6E /* Queuer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4995D7391F21E19B00A34E6E /* Queuer.framework */; }; 4995D76F1F21ED1C00A34E6E /* Queuer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4995D7661F21ED1B00A34E6E /* Queuer.framework */; }; 49B28E2C1F27EDCB00D0819A /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -71,6 +78,8 @@ /* Begin PBXFileReference section */ 493F57201F21F32B009EC8FA /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 493F57281F21F32B009EC8FA /* QueuerTests macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QueuerTests macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 4946BDF5214D586900FAFC84 /* Scheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scheduler.swift; sourceTree = ""; }; + 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchedulerTests.swift; sourceTree = ""; }; 4995D7391F21E19B00A34E6E /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4995D7421F21E19C00A34E6E /* QueuerTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QueuerTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 4995D7581F21EA3F00A34E6E /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -185,10 +194,9 @@ children = ( 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */, 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */, - 49C7BCB11F26938F00F4FFBC /* RequestOperationTests.swift */, + 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */, 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */, 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */, - 49C7BCB41F26938F00F4FFBC /* URLBuilderTests.swift */, ); path = QueuerTests; sourceTree = ""; @@ -211,10 +219,9 @@ children = ( 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */, 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */, - 49C7BCBD1F26938F00F4FFBC /* RequestOperation.swift */, + 4946BDF5214D586900FAFC84 /* Scheduler.swift */, 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */, 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */, - 49C7BCC01F26938F00F4FFBC /* URLBuilder.swift */, ); path = Queuer; sourceTree = ""; @@ -510,12 +517,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 49C7BCE31F26939A00F4FFBC /* RequestOperation.swift in Sources */, 49C7BCE21F26939A00F4FFBC /* Queuer.swift in Sources */, 49C7BCE41F26939A00F4FFBC /* Semaphore.swift in Sources */, 49C7BCE11F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */, + 4946BDF7214D586900FAFC84 /* Scheduler.swift in Sources */, 49C7BCE51F26939A00F4FFBC /* SynchronousOperation.swift in Sources */, - 49C7BCE61F26939A00F4FFBC /* URLBuilder.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -523,12 +529,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 49C7BCEF1F2693A000F4FFBC /* RequestOperationTests.swift in Sources */, 49C7BCEE1F2693A000F4FFBC /* QueuerTests.swift in Sources */, 49C7BCF01F2693A000F4FFBC /* SemaphoreTests.swift in Sources */, + 4946BDFC214D5C0100FAFC84 /* SchedulerTests.swift in Sources */, 49C7BCED1F2693A000F4FFBC /* ConcurrentOperationTests.swift in Sources */, 49C7BCF11F2693A000F4FFBC /* SynchronousOperationTests.swift in Sources */, - 49C7BCF21F2693A000F4FFBC /* URLBuilderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -539,9 +544,8 @@ 49C7BCCE1F26938F00F4FFBC /* ConcurrentOperation.swift in Sources */, 49C7BCD21F26938F00F4FFBC /* SynchronousOperation.swift in Sources */, 49C7BCCF1F26938F00F4FFBC /* Queuer.swift in Sources */, - 49C7BCD31F26938F00F4FFBC /* URLBuilder.swift in Sources */, + 4946BDF6214D586900FAFC84 /* Scheduler.swift in Sources */, 49C7BCD11F26938F00F4FFBC /* Semaphore.swift in Sources */, - 49C7BCD01F26938F00F4FFBC /* RequestOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -549,12 +553,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 49C7BCE91F26939F00F4FFBC /* RequestOperationTests.swift in Sources */, 49C7BCE81F26939F00F4FFBC /* QueuerTests.swift in Sources */, 49C7BCEA1F26939F00F4FFBC /* SemaphoreTests.swift in Sources */, + 4946BDFB214D5C0100FAFC84 /* SchedulerTests.swift in Sources */, 49C7BCE71F26939F00F4FFBC /* ConcurrentOperationTests.swift in Sources */, 49C7BCEB1F26939F00F4FFBC /* SynchronousOperationTests.swift in Sources */, - 49C7BCEC1F26939F00F4FFBC /* URLBuilderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -562,12 +565,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 49C7BCD71F26939900F4FFBC /* RequestOperation.swift in Sources */, 49C7BCD61F26939900F4FFBC /* Queuer.swift in Sources */, 49C7BCD81F26939900F4FFBC /* Semaphore.swift in Sources */, 49C7BCD51F26939900F4FFBC /* ConcurrentOperation.swift in Sources */, + 4946BDF9214D586900FAFC84 /* Scheduler.swift in Sources */, 49C7BCD91F26939900F4FFBC /* SynchronousOperation.swift in Sources */, - 49C7BCDA1F26939900F4FFBC /* URLBuilder.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -575,12 +577,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 49C7BCDD1F26939A00F4FFBC /* RequestOperation.swift in Sources */, 49C7BCDC1F26939A00F4FFBC /* Queuer.swift in Sources */, 49C7BCDE1F26939A00F4FFBC /* Semaphore.swift in Sources */, 49C7BCDB1F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */, + 4946BDF8214D586900FAFC84 /* Scheduler.swift in Sources */, 49C7BCDF1F26939A00F4FFBC /* SynchronousOperation.swift in Sources */, - 49C7BCE01F26939A00F4FFBC /* URLBuilder.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -588,12 +589,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 49C7BCF51F2693A100F4FFBC /* RequestOperationTests.swift in Sources */, 49C7BCF41F2693A100F4FFBC /* QueuerTests.swift in Sources */, 49C7BCF61F2693A100F4FFBC /* SemaphoreTests.swift in Sources */, + 4946BDFD214D5C0100FAFC84 /* SchedulerTests.swift in Sources */, 49C7BCF31F2693A100F4FFBC /* ConcurrentOperationTests.swift in Sources */, 49C7BCF71F2693A100F4FFBC /* SynchronousOperationTests.swift in Sources */, - 49C7BCF81F2693A100F4FFBC /* URLBuilderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/Queuer/Scheduler.swift b/Sources/Queuer/Scheduler.swift new file mode 100644 index 0000000..8e0216c --- /dev/null +++ b/Sources/Queuer/Scheduler.swift @@ -0,0 +1,61 @@ +// +// Scheduler.swift +// Queuer +// +// MIT License +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import Dispatch +import Foundation + +public struct Scheduler { + public private(set) var timer: DispatchSourceTimer + public private(set) var deadline: DispatchTime + public private(set) var repeating: DispatchTimeInterval + public private(set) var qualityOfService: DispatchQoS + public private(set) var handler: (() -> Void)? = nil + + public init(deadline: DispatchTime, repeating: DispatchTimeInterval, qualityOfService: DispatchQoS = .default, handler: (() -> Void)? = nil) { + self.deadline = deadline + self.repeating = repeating + self.qualityOfService = qualityOfService + self.handler = handler + + timer = DispatchSource.makeTimerSource() + timer.schedule(deadline: deadline, repeating: repeating) + if let handler = handler { + timer.setEventHandler(qos: qualityOfService) { + handler() + } + timer.resume() + } + } + + public mutating func setHandler(_ handler: @escaping () -> Void) { + self.handler = handler + + timer.setEventHandler(qos: qualityOfService) { + handler() + } + timer.resume() + } +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index c1defa8..3f8de96 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -31,6 +31,7 @@ import XCTest XCTMain([ testCase(ConcurrentOperationTests.allTests), testCase(QueuerTests.allTests), + testCase(SchedulerTests.allTests), testCase(SemaphoreTests.allTests), testCase(SynchronousOperationTests.allTests) ]) diff --git a/Tests/QueuerTests/SchedulerTests.swift b/Tests/QueuerTests/SchedulerTests.swift new file mode 100644 index 0000000..ed2db2f --- /dev/null +++ b/Tests/QueuerTests/SchedulerTests.swift @@ -0,0 +1,63 @@ +// +// SchedulerTests.swift +// Queuer +// +// MIT License +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import Dispatch +@testable import Queuer +import XCTest + +internal class SchedulerTests: XCTestCase { + internal static let allTests = [ + ("testInitWithoutHandler", testInitWithoutHandler), + ("testInitWithHandler", testInitWithHandler) + ] + + internal func testInitWithoutHandler() { + let testExpectation = expectation(description: "Init Without Handler") + + var schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) + schedule.setHandler { + testExpectation.fulfill() + schedule.timer.cancel() + } + + waitForExpectations(timeout: 2) { error in + XCTAssertNil(error) + } + } + + internal func testInitWithHandler() { + let testExpectation = expectation(description: "Init With Handler") + + let schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 2) { error in + XCTAssertNil(error) + schedule.timer.cancel() + } + } +} From 9cae3f744b7766732a869ea0ad9bfc1732a96f87 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 15 Sep 2018 18:17:49 +0200 Subject: [PATCH 21/57] Improving documentation --- README.md | 22 ++++++++++++++++++++++ Sources/Queuer/Scheduler.swift | 16 ++++++++++++++++ Tests/QueuerTests/SchedulerTests.swift | 2 +- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c718e7e..91bc9eb 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,28 @@ let synchronousOperation = SynchronousOperation { synchronousOperation.addToQueue(queue) ``` +### Scheduler +A `Scheduler` is a struct that uses the GDC's `DispatchSourceTimer` to create a timer that can execute functions with a specified interval and quality of service. + +```swift +let schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) { + /// Your task here +} +``` + +You can even create a `Scheduler` without the handler and set it later: +```swift +var schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) +schedule.setHandler { + /// Your task here. +} +``` + +With `timer` property you can access to all `DispatchSourceTimer` properties and functions, like `cancel()`: +```swift +schedule.timer.cancel() +``` + ### Semaphore A `Semaphore` is a struct that uses the GCD's `DispatchSemaphore` to create a semaphore on the function and wait until it finish its job.
I recommend you to use a `defer { semaphore.continue() }` right after the `Semaphore` creation and `wait()` call. diff --git a/Sources/Queuer/Scheduler.swift b/Sources/Queuer/Scheduler.swift index 8e0216c..1dc5137 100644 --- a/Sources/Queuer/Scheduler.swift +++ b/Sources/Queuer/Scheduler.swift @@ -27,13 +27,26 @@ import Dispatch import Foundation +/// Scheduler struct, based on top of `DispatchSourceTimer`. public struct Scheduler { + /// Schedule timer. public private(set) var timer: DispatchSourceTimer + /// Schedule deadline. public private(set) var deadline: DispatchTime + /// Schedule repeating interval. public private(set) var repeating: DispatchTimeInterval + /// Schedule quality of service. public private(set) var qualityOfService: DispatchQoS + /// Schedule handler. public private(set) var handler: (() -> Void)? = nil + /// Create a schedule. + /// + /// - Parameters: + /// - deadline: Deadline. + /// - repeating: Repeating interval + /// - qualityOfService: Quality of service. + /// - handler: Closure handler. public init(deadline: DispatchTime, repeating: DispatchTimeInterval, qualityOfService: DispatchQoS = .default, handler: (() -> Void)? = nil) { self.deadline = deadline self.repeating = repeating @@ -50,6 +63,9 @@ public struct Scheduler { } } + /// Set the handler after schedule creation. + /// + /// - Parameter handler: Closure handler. public mutating func setHandler(_ handler: @escaping () -> Void) { self.handler = handler diff --git a/Tests/QueuerTests/SchedulerTests.swift b/Tests/QueuerTests/SchedulerTests.swift index ed2db2f..c4cf963 100644 --- a/Tests/QueuerTests/SchedulerTests.swift +++ b/Tests/QueuerTests/SchedulerTests.swift @@ -51,7 +51,7 @@ internal class SchedulerTests: XCTestCase { internal func testInitWithHandler() { let testExpectation = expectation(description: "Init With Handler") - let schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) { + let schedule = Scheduler(deadline: .now(), repeating: .never) { testExpectation.fulfill() } From d66b913ba82d15bdf4cd8db1067fc7a23cb141b7 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 16 Sep 2018 19:30:40 +0200 Subject: [PATCH 22/57] Updating README --- README.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 91bc9eb..dfb3fae 100644 --- a/README.md +++ b/README.md @@ -38,32 +38,29 @@ Queuer is a queue manager, built on top of [OperationQueue](https://developer.ap It allows you to create any synchronous and asynchronous task easily, with just a few lines. Here is the list of all the features: -- [x] Works on all Swift compatible platforms (even Linux `*`) +- [x] Works on all Swift compatible platforms (even Linux) - [x] Easy to use - [x] Well documented (100% documented) -- [x] Well tested (currently 99% of code coverage) +- [x] Well tested (100% of code coverage) - [x] Create an operation block - [x] Create a single operation - [x] Create chained operations - [x] Manage a centralized queue - [x] Create unlimited queue - [x] Declare how many concurrent operation a queue can handle +- [x] Create semaphores +- [x] Create and handle schedules - [ ] Ability to restore uncompleted operations -- [ ] Wrappers for other frameworks (like Alamofire, Moya, ecc) maybe with pod subspecs - -> `*` Currently, `URLSession.shared` property is not yet implemented on Linux. Requirements ============ | **Swift** | **Xcode** | **Queuer** | **iOS** | **macOS** | **tvOS** | **watchOS** | **Linux** | |-----------|-----------|---------------|---------|------------|-----------|-------------|-----------| -| 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | -| 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | -| 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | -| 4.2 | 10.0 | 2.x.x | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] `*` | - -> `*` Currently, `URLSession.shared` property is not yet implemented on Linux. +| 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | +| 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | +| 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | +| 4.2 | 10.0 | 2.x.x | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | Installing ========== From 79d1ead2b50213533f9e5b49dd8b14f017d7527a Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 17 Sep 2018 01:00:34 +0200 Subject: [PATCH 23/57] Minor change --- Sources/Queuer/Scheduler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Queuer/Scheduler.swift b/Sources/Queuer/Scheduler.swift index 1dc5137..12014e0 100644 --- a/Sources/Queuer/Scheduler.swift +++ b/Sources/Queuer/Scheduler.swift @@ -38,7 +38,7 @@ public struct Scheduler { /// Schedule quality of service. public private(set) var qualityOfService: DispatchQoS /// Schedule handler. - public private(set) var handler: (() -> Void)? = nil + public private(set) var handler: (() -> Void)? /// Create a schedule. /// From 4260749d6b203a9bfc0ee3166989362fb39607f2 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 17 Sep 2018 01:23:11 +0200 Subject: [PATCH 24/57] Adding `addCompletionHandler(_:)` function --- Sources/Queuer/Queuer.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Sources/Queuer/Queuer.swift b/Sources/Queuer/Queuer.swift index 49796bc..8a7a3df 100644 --- a/Sources/Queuer/Queuer.swift +++ b/Sources/Queuer/Queuer.swift @@ -120,11 +120,7 @@ public class Queuer { return } - let completionOperation = BlockOperation(block: completionHandler) - if !operations.isEmpty { - completionOperation.addDependency(operations[operations.count - 1]) - } - addOperation(completionOperation) + addCompletionHandler(completionHandler) } /// Add an Array of chained Operations. @@ -141,6 +137,17 @@ public class Queuer { addChainedOperations(operations, completionHandler: completionHandler) } + /// Add a completion block to the queue. + /// + /// - Parameter completionHandler: Completion handler to be executed as last operation. + public func addCompletionHandler(_ completionHandler: @escaping () -> Void) { + let completionOperation = BlockOperation(block: completionHandler) + if let lastOperation = operations.last { + completionOperation.addDependency(lastOperation) + } + addOperation(completionOperation) + } + /// Cancel all Operations in queue. public func cancelAll() { queue.cancelAllOperations() From fc3a20f00b04289a071d57758c25efecc591c42b Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 17 Sep 2018 01:23:48 +0200 Subject: [PATCH 25/57] Adding retry feature #10 --- Sources/Queuer/ConcurrentOperation.swift | 38 +++++++++++++++---- Sources/Queuer/SynchronousOperation.swift | 8 +++- .../ConcurrentOperationTests.swift | 2 +- Tests/QueuerTests/QueuerTests.swift | 34 ++++++++--------- Tests/QueuerTests/SemaphoreTests.swift | 4 +- .../SynchronousOperationTests.swift | 12 +++--- 6 files changed, 63 insertions(+), 35 deletions(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index 2906a98..e1132ea 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -29,12 +29,12 @@ import Foundation /// It allows asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block. open class ConcurrentOperation: Operation { /// Operation's execution block. - public var executionBlock: (() -> Void)? + public var executionBlock: ((_ operation: ConcurrentOperation) -> Void)? /// Creates the Operation with an execution block. /// /// - Parameter executionBlock: Execution block. - public init(executionBlock: (() -> Void)? = nil) { + public init(executionBlock: ((_ operation: ConcurrentOperation) -> Void)? = nil) { super.init() self.executionBlock = executionBlock @@ -75,6 +75,20 @@ open class ConcurrentOperation: Operation { return _finished } + /// You should use `hasFailed` if retry is enabled. + /// Set it to `true` if the operation has failed, otherwise `false`. + /// Default is `false` to avoid retries. + open var hasFailed = false + + /// Maximum allowed retries. + open var maximumRetries = 3 + + /// Current retry tentative. + open var currentRetry = 0 + + /// Specify if the operation should retry another time. + private var shouldRetry = true + /// Start the Operation. override open func start() { _executing = true @@ -85,16 +99,26 @@ open class ConcurrentOperation: Operation { /// If `executionBlock` is set, it will be executed and also `finish()` will be called. open func execute() { if let executionBlock = executionBlock { - executionBlock() - self.finish() + while shouldRetry { + executionBlock(self) + self.finish(hasFailed) + } } } /// Notify the completion of async task and hence the completion of the operation. /// Must be called when the Operation is finished. - open func finish() { - _executing = false - _finished = true + /// + /// - Parameter hasFailed: Set it to `true` if the operation has failed, otherwise `false`. + open func finish(_ hasFailed: Bool) { + if !hasFailed || currentRetry >= maximumRetries { + _executing = false + _finished = true + shouldRetry = false + } else { + currentRetry += 1 + shouldRetry = true + } } /// Pause the current Operation, if it's supported. diff --git a/Sources/Queuer/SynchronousOperation.swift b/Sources/Queuer/SynchronousOperation.swift index db89b70..c9a5b02 100644 --- a/Sources/Queuer/SynchronousOperation.swift +++ b/Sources/Queuer/SynchronousOperation.swift @@ -36,9 +36,13 @@ public class SynchronousOperation: ConcurrentOperation { return false } - /// Notify the completion of sync task and hence the completion of the operation. + /// Notify the completion of async task and hence the completion of the operation. /// Must be called when the Operation is finished. - override public func finish() { + /// + /// - Parameter hasFailed: Set it to `true` if the operation has failed, otherwise `false`. + override public func finish(_ hasFailed: Bool) { + super.finish(hasFailed) + semaphore.continue() } diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 90a6a74..c60ebdb 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -40,7 +40,7 @@ internal class ConcurrentOperationTests: XCTestCase { let testExpectation = expectation(description: "Init With Execution Block") - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in testExpectation.fulfill() } concurrentOperation.addToQueue(queue) diff --git a/Tests/QueuerTests/QueuerTests.swift b/Tests/QueuerTests/QueuerTests.swift index 16e50ec..b591e27 100644 --- a/Tests/QueuerTests/QueuerTests.swift +++ b/Tests/QueuerTests/QueuerTests.swift @@ -55,7 +55,7 @@ internal class QueuerTests: XCTestCase { XCTAssertEqual(queue.operationCount, 0) - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testExpectation.fulfill() } @@ -72,7 +72,7 @@ internal class QueuerTests: XCTestCase { let queue = Queuer(name: "QueuerTestOperations") let testExpectation = expectation(description: "Operations") - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testExpectation.fulfill() } @@ -137,7 +137,7 @@ internal class QueuerTests: XCTestCase { let queue = Queuer(name: "QueuerTestAddOperation") let testExpectation = expectation(description: "Add Operation") - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in XCTAssertEqual(queue.operationCount, 1) testExpectation.fulfill() } @@ -154,10 +154,10 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Add Operations") var check = 0 - let concurrentOperation1 = ConcurrentOperation { + let concurrentOperation1 = ConcurrentOperation { _ in check += 1 } - let concurrentOperation2 = ConcurrentOperation { + let concurrentOperation2 = ConcurrentOperation { _ in check += 1 } queue.addOperation(concurrentOperation1) @@ -180,11 +180,11 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Add Chained Operations") var order: [Int] = [] - let concurrentOperation1 = ConcurrentOperation { + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) } - let concurrentOperation2 = ConcurrentOperation { + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { @@ -203,11 +203,11 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Add Chained Operations List") var order: [Int] = [] - let concurrentOperation1 = ConcurrentOperation { + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) } - let concurrentOperation2 = ConcurrentOperation { + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) } queue.addChainedOperations(concurrentOperation1, concurrentOperation2) { @@ -240,10 +240,10 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Add Chained Operations Without Completion") var order: [Int] = [] - let concurrentOperation1 = ConcurrentOperation { + let concurrentOperation1 = ConcurrentOperation { _ in order.append(0) } - let concurrentOperation2 = ConcurrentOperation { + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) testExpectation.fulfill() } @@ -261,11 +261,11 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Cancell All Operations") var order: [Int] = [] - let concurrentOperation1 = SynchronousOperation { + let concurrentOperation1 = SynchronousOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) } - let concurrentOperation2 = SynchronousOperation { + let concurrentOperation2 = SynchronousOperation { _ in order.append(1) } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { @@ -290,11 +290,11 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Pause and Resume") var order: [Int] = [] - let concurrentOperation1 = ConcurrentOperation { + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) } - let concurrentOperation2 = ConcurrentOperation { + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { @@ -322,11 +322,11 @@ internal class QueuerTests: XCTestCase { let testExpectation = expectation(description: "Wait Unitl All Operations Are Finished") var order: [Int] = [] - let concurrentOperation1 = ConcurrentOperation { + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) } - let concurrentOperation2 = ConcurrentOperation { + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { diff --git a/Tests/QueuerTests/SemaphoreTests.swift b/Tests/QueuerTests/SemaphoreTests.swift index 82f08f6..698fa34 100644 --- a/Tests/QueuerTests/SemaphoreTests.swift +++ b/Tests/QueuerTests/SemaphoreTests.swift @@ -39,7 +39,7 @@ internal class SemaphoreTests: XCTestCase { let testExpectation = expectation(description: "With Semaphore") var testString = "" - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testString = "Tested" semaphore.continue() @@ -60,7 +60,7 @@ internal class SemaphoreTests: XCTestCase { let testExpectation = expectation(description: "Without Semaphore") var testString = "" - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testString = "Tested" testExpectation.fulfill() diff --git a/Tests/QueuerTests/SynchronousOperationTests.swift b/Tests/QueuerTests/SynchronousOperationTests.swift index b0dcffa..9b9fd8d 100644 --- a/Tests/QueuerTests/SynchronousOperationTests.swift +++ b/Tests/QueuerTests/SynchronousOperationTests.swift @@ -40,10 +40,10 @@ internal class SynchronousOperationTests: XCTestCase { let testExpectation = expectation(description: "Synchronous Operation") var testString = "" - let synchronousOperation1 = SynchronousOperation { + let synchronousOperation1 = SynchronousOperation { _ in testString = "Tested1" } - let synchronousOperation2 = SynchronousOperation { + let synchronousOperation2 = SynchronousOperation { _ in Thread.sleep(forTimeInterval: 2) testString = "Tested2" @@ -65,10 +65,10 @@ internal class SynchronousOperationTests: XCTestCase { let testExpectation = expectation(description: "Synchronous Operation") var testString = "" - let synchronousOperation1 = SynchronousOperation { + let synchronousOperation1 = SynchronousOperation { _ in testString = "Tested1" } - let synchronousOperation2 = SynchronousOperation { + let synchronousOperation2 = SynchronousOperation { _ in Thread.sleep(forTimeInterval: 2) testString = "Tested2" @@ -98,11 +98,11 @@ internal class SynchronousOperationTests: XCTestCase { testExpectation.fulfill() } - let synchronousOperation1 = SynchronousOperation { + let synchronousOperation1 = SynchronousOperation { _ in testString = "Tested1" Thread.sleep(forTimeInterval: 4) } - let synchronousOperation2 = SynchronousOperation { + let synchronousOperation2 = SynchronousOperation { _ in testString = "Tested2" } synchronousOperation1.addToQueue(queue) From 2ea83764510a0f547de805a24862f6acf62e200f Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 17 Sep 2018 01:24:00 +0200 Subject: [PATCH 26/57] Updating CHANGELOG --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20e370f..6ace826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,16 @@ All notable changes to this project will be documented in this file.
## Swift 4.2 ### Added - Added support to Xcode 10 and Swift 4.2 +- Added retry feature to `ConcurrentOperation` class [#32](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10) +- Added `addCompletionHandler(_:)` function to `Queuer` class ### Changed +- Changed `executionBlock` of `ConcurrentOperation` to pass the `concurrentOperation` variable inside the closure to be able to use the retry feature. If you don't need it simply put `_ in` after the block creation + ```swift + let concurrentOperation = ConcurrentOperation { _ in + /// Your task here + } + ``` - Changed from Codecov to Coveralls service for code coverage --- @@ -105,7 +113,7 @@ Thanks to [@BabyAzerty](https://github.com/BabyAzerty) for this release - Updated SwiftLint to 0.21.0 ### Fixed -- Now `ConcurrentOperation` is subclassable with `open` instead of `public` Access Control [#2](https://github.com/FabrizioBrancati/Queuer/issue/2) +- Now `ConcurrentOperation` is subclassable with `open` instead of `public` Access Control [#2](https://github.com/FabrizioBrancati/Queuer/issues/2) - Fixed tests that sometimes fails --- From 95e424f4c6343524c5194d3e50c360e93ef44bb8 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Wed, 19 Sep 2018 00:57:23 +0200 Subject: [PATCH 27/57] Auto-generating Linux tests --- .travis.yml | 3 +- Tests/LinuxMain.swift | 30 ++- .../ConcurrentOperationTests+XCTest.swift | 45 ++++ .../ConcurrentOperationTests.swift | 7 - Tests/QueuerTests/QueuerTests+XCTest.swift | 57 ++++ Tests/QueuerTests/QueuerTests.swift | 19 -- Tests/QueuerTests/SchedulerTests+XCTest.swift | 43 +++ Tests/QueuerTests/SchedulerTests.swift | 7 +- Tests/QueuerTests/SemaphoreTests+XCTest.swift | 43 +++ Tests/QueuerTests/SemaphoreTests.swift | 5 - .../SynchronousOperationTests+XCTest.swift | 44 ++++ .../SynchronousOperationTests.swift | 6 - generate_linux_tests.rb | 245 ++++++++++++++++++ 13 files changed, 499 insertions(+), 55 deletions(-) create mode 100644 Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift create mode 100644 Tests/QueuerTests/QueuerTests+XCTest.swift create mode 100644 Tests/QueuerTests/SchedulerTests+XCTest.swift create mode 100644 Tests/QueuerTests/SemaphoreTests+XCTest.swift create mode 100644 Tests/QueuerTests/SynchronousOperationTests+XCTest.swift create mode 100644 generate_linux_tests.rb diff --git a/.travis.yml b/.travis.yml index 689bbc2..8e411c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -88,7 +88,8 @@ script: - swift -version - if [ "$SPM" == "YES" ]; then - swift build; + swift package clean; + ruby generate_linux_tests.rb; swift test --parallel; fi diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 3f8de96..e545a75 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -2,9 +2,9 @@ // LinuxMain.swift // Queuer // -// MIT License +// The MIT License (MIT) // -// Copyright (c) 2017 - 2018 Fabrizio Brancati +// Copyright (c) 2017 - 2018 Fabrizio Brancati. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -23,16 +23,24 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// -#if os(Linux) -@testable import QueuerTests import XCTest -XCTMain([ - testCase(ConcurrentOperationTests.allTests), - testCase(QueuerTests.allTests), - testCase(SchedulerTests.allTests), - testCase(SemaphoreTests.allTests), - testCase(SynchronousOperationTests.allTests) -]) +#if os(Linux) || os(FreeBSD) + @testable import QueuerTests + + XCTMain([ + testCase(ConcurrentOperationTests.allTests), + testCase(QueuerTests.allTests), + testCase(SchedulerTests.allTests), + testCase(SemaphoreTests.allTests), + testCase(SynchronousOperationTests.allTests) + ]) #endif diff --git a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift new file mode 100644 index 0000000..8fa163b --- /dev/null +++ b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift @@ -0,0 +1,45 @@ +// +// ConcurrentOperationTests+XCTest.swift +// Queuer +// +// The MIT License (MIT) +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// + +import XCTest + +internal extension ConcurrentOperationTests { + internal static var allTests: [(String, (ConcurrentOperationTests) -> () throws -> Void)] { + return [ + ("testInitWithExecutionBlock", testInitWithExecutionBlock), + ("testIsAsynchronous", testIsAsynchronous), + ("testAddToSharedQueuer", testAddToSharedQueuer), + ("testAddToQueue", testAddToQueue) + ] + } +} diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index c60ebdb..863c828 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -28,13 +28,6 @@ import XCTest internal class ConcurrentOperationTests: XCTestCase { - internal static let allTests = [ - ("testInitWithExecutionBlock", testInitWithExecutionBlock), - ("testIsAsynchronous", testIsAsynchronous), - ("testAddToSharedQueuer", testAddToSharedQueuer), - ("testAddToQueue", testAddToQueue) - ] - internal func testInitWithExecutionBlock() { let queue = Queuer(name: "ConcurrentOperationTestInitWithExecutionBlock") diff --git a/Tests/QueuerTests/QueuerTests+XCTest.swift b/Tests/QueuerTests/QueuerTests+XCTest.swift new file mode 100644 index 0000000..b2fe8d1 --- /dev/null +++ b/Tests/QueuerTests/QueuerTests+XCTest.swift @@ -0,0 +1,57 @@ +// +// QueuerTests+XCTest.swift +// Queuer +// +// The MIT License (MIT) +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// + +import XCTest + +internal extension QueuerTests { + internal static var allTests: [(String, (QueuerTests) -> () throws -> Void)] { + return [ + ("testOperationCount", testOperationCount), + ("testOperations", testOperations), + ("testMaxConcurrentOperationCount", testMaxConcurrentOperationCount), + ("testQualityOfService", testQualityOfService), + ("testInitWithNameMaxConcurrentOperationCount", testInitWithNameMaxConcurrentOperationCount), + ("testInitWithNameMaxConcurrentOperationCountQualityOfService", testInitWithNameMaxConcurrentOperationCountQualityOfService), + ("testAddOperationBlock", testAddOperationBlock), + ("testAddOperation", testAddOperation), + ("testAddOperations", testAddOperations), + ("testAddChainedOperations", testAddChainedOperations), + ("testAddChainedOperationsList", testAddChainedOperationsList), + ("testAddChainedOperationsEmpty", testAddChainedOperationsEmpty), + ("testAddChainedOperationsWithoutCompletion", testAddChainedOperationsWithoutCompletion), + ("testCancelAll", testCancelAll), + ("testPauseAndResume", testPauseAndResume), + ("testWaitUnitlAllOperationsAreFinished", testWaitUnitlAllOperationsAreFinished) + ] + } +} diff --git a/Tests/QueuerTests/QueuerTests.swift b/Tests/QueuerTests/QueuerTests.swift index b591e27..f9e2342 100644 --- a/Tests/QueuerTests/QueuerTests.swift +++ b/Tests/QueuerTests/QueuerTests.swift @@ -30,25 +30,6 @@ import XCTest // swiftlint:disable type_body_length internal class QueuerTests: XCTestCase { - internal static let allTests = [ - ("testOperationCount", testOperationCount), - ("testOperations", testOperations), - ("testMaxConcurrentOperationCount", testMaxConcurrentOperationCount), - ("testQualityOfService", testQualityOfService), - ("testInitWithNameMaxConcurrentOperationCount", testInitWithNameMaxConcurrentOperationCount), - ("testInitWithNameMaxConcurrentOperationCountQualityOfService", testInitWithNameMaxConcurrentOperationCountQualityOfService), - ("testAddOperationBlock", testAddOperationBlock), - ("testAddOperation", testAddOperation), - ("testAddOperations", testAddOperations), - ("testAddChainedOperations", testAddChainedOperations), - ("testAddChainedOperationsList", testAddChainedOperationsList), - ("testAddChainedOperationsEmpty", testAddChainedOperationsEmpty), - ("testAddChainedOperationsWithoutCompletion", testAddChainedOperationsWithoutCompletion), - ("testCancelAll", testCancelAll), - ("testPauseAndResume", testPauseAndResume), - ("testWaitUnitlAllOperationsAreFinished", testWaitUnitlAllOperationsAreFinished) - ] - internal func testOperationCount() { let queue = Queuer(name: "QueuerTestOperationCount") let testExpectation = expectation(description: "Operation Count") diff --git a/Tests/QueuerTests/SchedulerTests+XCTest.swift b/Tests/QueuerTests/SchedulerTests+XCTest.swift new file mode 100644 index 0000000..4523b2e --- /dev/null +++ b/Tests/QueuerTests/SchedulerTests+XCTest.swift @@ -0,0 +1,43 @@ +// +// SchedulerTests+XCTest.swift +// Queuer +// +// The MIT License (MIT) +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// + +import XCTest + +internal extension SchedulerTests { + internal static var allTests: [(String, (SchedulerTests) -> () throws -> Void)] { + return [ + ("testInitWithoutHandler", testInitWithoutHandler), + ("testInitWithHandler", testInitWithHandler) + ] + } +} diff --git a/Tests/QueuerTests/SchedulerTests.swift b/Tests/QueuerTests/SchedulerTests.swift index c4cf963..ddbc1ce 100644 --- a/Tests/QueuerTests/SchedulerTests.swift +++ b/Tests/QueuerTests/SchedulerTests.swift @@ -28,12 +28,7 @@ import Dispatch @testable import Queuer import XCTest -internal class SchedulerTests: XCTestCase { - internal static let allTests = [ - ("testInitWithoutHandler", testInitWithoutHandler), - ("testInitWithHandler", testInitWithHandler) - ] - +internal class SchedulerTests: XCTestCase { internal func testInitWithoutHandler() { let testExpectation = expectation(description: "Init Without Handler") diff --git a/Tests/QueuerTests/SemaphoreTests+XCTest.swift b/Tests/QueuerTests/SemaphoreTests+XCTest.swift new file mode 100644 index 0000000..e773f9a --- /dev/null +++ b/Tests/QueuerTests/SemaphoreTests+XCTest.swift @@ -0,0 +1,43 @@ +// +// SemaphoreTests+XCTest.swift +// Queuer +// +// The MIT License (MIT) +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// + +import XCTest + +internal extension SemaphoreTests { + internal static var allTests: [(String, (SemaphoreTests) -> () throws -> Void)] { + return [ + ("testWithSemaphore", testWithSemaphore), + ("testWithoutSemaphore", testWithoutSemaphore) + ] + } +} diff --git a/Tests/QueuerTests/SemaphoreTests.swift b/Tests/QueuerTests/SemaphoreTests.swift index 698fa34..038f186 100644 --- a/Tests/QueuerTests/SemaphoreTests.swift +++ b/Tests/QueuerTests/SemaphoreTests.swift @@ -28,11 +28,6 @@ import XCTest internal class SemaphoreTests: XCTestCase { - internal static let allTests = [ - ("testWithSemaphore", testWithSemaphore), - ("testWithoutSemaphore", testWithoutSemaphore) - ] - internal func testWithSemaphore() { let semaphore = Semaphore() let queue = Queuer(name: "SemaphoreTestWithSemaphore") diff --git a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift new file mode 100644 index 0000000..9bbdaa7 --- /dev/null +++ b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift @@ -0,0 +1,44 @@ +// +// SynchronousOperationTests+XCTest.swift +// Queuer +// +// The MIT License (MIT) +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// + +import XCTest + +internal extension SynchronousOperationTests { + internal static var allTests: [(String, (SynchronousOperationTests) -> () throws -> Void)] { + return [ + ("testSynchronousOperation", testSynchronousOperation), + ("testSynchronousOperationOnSharedQueuer", testSynchronousOperationOnSharedQueuer), + ("testCancel", testCancel) + ] + } +} diff --git a/Tests/QueuerTests/SynchronousOperationTests.swift b/Tests/QueuerTests/SynchronousOperationTests.swift index 9b9fd8d..b542a31 100644 --- a/Tests/QueuerTests/SynchronousOperationTests.swift +++ b/Tests/QueuerTests/SynchronousOperationTests.swift @@ -29,12 +29,6 @@ import Dispatch import XCTest internal class SynchronousOperationTests: XCTestCase { - internal static let allTests = [ - ("testSynchronousOperation", testSynchronousOperation), - ("testSynchronousOperationOnSharedQueuer", testSynchronousOperationOnSharedQueuer), - ("testCancel", testCancel) - ] - internal func testSynchronousOperation() { let queue = Queuer(name: "SynchronousOperationTestSynchronousOperation") let testExpectation = expectation(description: "Synchronous Operation") diff --git a/generate_linux_tests.rb b/generate_linux_tests.rb new file mode 100644 index 0000000..4e732e8 --- /dev/null +++ b/generate_linux_tests.rb @@ -0,0 +1,245 @@ +#!/usr/bin/env ruby + +# +# process_test_files.rb +# +# Copyright 2016 Tony Stone +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Created by Tony Stone on 5/4/16. +# +require 'getoptlong' +require 'fileutils' +require 'pathname' + +include FileUtils + +# +# This ruby script will auto generate LinuxMain.swift and the +XCTest.swift extension files for Swift Package Manager on Linux platforms. +# +# See https://github.com/apple/swift-corelibs-xctest/blob/master/Documentation/Linux.md +# +def header(file_name) + string = <<-eos +// +// +// Queuer +// +// The MIT License (MIT) +// +// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// +// +// NOTE: This file was generated by generate_linux_tests.rb +// +// Do NOT edit this file directly as it will be regenerated automatically when needed. +// + +import XCTest + eos + + string + .sub('', File.basename(file_name)) + .sub('', Time.now.to_s) +end + +def create_extension_file(file_name, classes) + extension_file = file_name.sub! '.swift', '+XCTest.swift' + print 'Creating file: ' + extension_file + "\n" + + File.open(extension_file, 'w') do |file| + file.write header(extension_file) + file.write "\n" + + for class_array in classes + file.write 'internal extension ' + class_array[0] + " {\n" + file.write ' internal static var allTests: [(String, (' + class_array[0] + ") -> () throws -> Void)] {\n" + file.write " return [\n" + + class_count = class_array[1].size + count = 0 + for func_name in class_array[1] + count += 1 + + file.write ' ("' + func_name + '", ' + func_name + (count == class_count ? ")\n" : "),\n") + end + + file.write " ]\n" + file.write " }\n" + file.write "}\n" + end + end +end + +def create_linux_main(tests_directory, all_test_sub_directories, files) + file_name = tests_directory + '/LinuxMain.swift' + print 'Creating file: ' + file_name + "\n" + + File.open(file_name, 'w') do |file| + file.write header(file_name) + file.write "\n" + + file.write "#if os(Linux) || os(FreeBSD)\n" + for test_sub_directory in all_test_sub_directories.sort { |x, y| x <=> y } + file.write ' @testable import ' + test_sub_directory + "\n" + end + file.write "\n" + file.write " XCTMain([\n" + + test_cases = [] + for classes in files + for class_array in classes + test_cases << class_array[0] + end + end + + cases_count = test_cases.size + count = 0 + for test_case in test_cases.sort { |x, y| x <=> y } + count += 1 + + file.write ' testCase(' + test_case + (count == cases_count ? ".allTests)\n" : ".allTests),\n") + end + file.write " ])\n" + file.write "#endif\n" + end +end + +def parse_source_file(file_name) + puts 'Parsing file: ' + file_name + "\n" + + classes = [] + current_class = nil + in_if_linux = false + in_else = false + ignore = false + + # + # Read the file line by line + # and parse to find the class + # names and func names + # + File.readlines(file_name).each do |line| + if in_if_linux + if /\#else/ =~ line + in_else = true + ignore = true + elsif /\#end/ =~ line + in_else = false + in_if_linux = false + ignore = false + end + elsif /\#if[ \t]+os\(Linux\)/ =~ line + in_if_linux = true + ignore = false + end + + next if ignore + # Match class or func + match = line[/class[ \t]+[a-zA-Z0-9_]*(?=[ \t]*:[ \t]*XCTestCase)|func[ \t]+test[a-zA-Z0-9_]*(?=[ \t]*\(\))/, 0] + if match + if match[/class/, 0] == 'class' + class_name = match.sub(/^class[ \t]+/, '') + # + # Create a new class / func structure + # and add it to the classes array. + # + current_class = [class_name, []] + classes << current_class + else # Must be a func + func_name = match.sub(/^func[ \t]+/, '') + # + # Add each func name the the class / func + # structure created above. + # + current_class[1] << func_name + end + end + end + classes +end + +# +# Main routine +# +# + +tests_directory = 'Tests' + +options = GetoptLong.new(['--tests-dir', GetoptLong::OPTIONAL_ARGUMENT]) +options.quiet = true + +begin + options.each do |option, value| + case option + when '--tests-dir' + tests_directory = value + end + end + rescue GetoptLong::InvalidOption +end + +all_test_sub_directories = [] +all_files = [] + +Dir[tests_directory + '/*'].each do |sub_directory| + next unless File.directory?(sub_directory) + directory_has_classes = false + Dir[sub_directory + '/*Test{s,}.swift'].each do |file_name| + next unless File.file? file_name + file_classes = parse_source_file(file_name) + + # + # If there are classes in the + # test source file, create an extension + # file for it. + # + next unless file_classes.count.positive? + create_extension_file(file_name, file_classes) + directory_has_classes = true + all_files << file_classes + end + + if directory_has_classes + all_test_sub_directories << Pathname.new(sub_directory).split.last.to_s + end +end + +# +# Last step is the create a LinuxMain.swift file that +# references all the classes and funcs in the source files. +# +if all_files.count.positive? + create_linux_main(tests_directory, all_test_sub_directories, all_files) +end +# eof From dbcc3405d292fb4fe5d1101f7593c0649be5a438 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Wed, 19 Sep 2018 23:50:22 +0200 Subject: [PATCH 28/57] Adding new tests --- Sources/Queuer/ConcurrentOperation.swift | 6 +-- .../ConcurrentOperationTests.swift | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index e1132ea..513ba66 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -84,7 +84,7 @@ open class ConcurrentOperation: Operation { open var maximumRetries = 3 /// Current retry tentative. - open var currentRetry = 0 + open var currentAttempt = 1 /// Specify if the operation should retry another time. private var shouldRetry = true @@ -111,12 +111,12 @@ open class ConcurrentOperation: Operation { /// /// - Parameter hasFailed: Set it to `true` if the operation has failed, otherwise `false`. open func finish(_ hasFailed: Bool) { - if !hasFailed || currentRetry >= maximumRetries { + if !hasFailed || currentAttempt >= maximumRetries { _executing = false _finished = true shouldRetry = false } else { - currentRetry += 1 + currentAttempt += 1 shouldRetry = true } } diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 863c828..0c8bcfc 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -66,4 +66,49 @@ internal class ConcurrentOperationTests: XCTestCase { XCTAssertEqual(queue.operationCount, 1) XCTAssertEqual(queue.operations, [concurrentOperation]) } + + internal func testSimpleRetry() { + let queue = Queuer(name: "ConcurrentOperationTestSimpleRetry") + + let testExpectation = expectation(description: "Simple Retry") + + let concurrentOperation = ConcurrentOperation { operation in + operation.hasFailed = true + } + concurrentOperation.addToQueue(queue) + queue.addCompletionHandler { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertTrue(concurrentOperation.hasFailed) + XCTAssertEqual(concurrentOperation.currentAttempt, 3) + } + } + + internal func testChainedRetry() { + let queue = Queuer(name: "ConcurrentOperationTestChainedRetry") + let testExpectation = expectation(description: "Chained Retry") + var order: [Int] = [] + + let concurrentOperation1 = ConcurrentOperation { operation in + Thread.sleep(forTimeInterval: 1) + order.append(0) + operation.hasFailed = true + } + let concurrentOperation2 = ConcurrentOperation { operation in + order.append(1) + operation.hasFailed = true + } + queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { + order.append(2) + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2]) + } + } } From 793257ab7beaa50e9c02979e528c73940c4a61d8 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Thu, 20 Sep 2018 00:05:39 +0200 Subject: [PATCH 29/57] Resolving SwiftLint issues --- Sources/Queuer/ConcurrentOperation.swift | 18 +++++++++--------- Tests/LinuxMain.swift | 4 ++-- .../ConcurrentOperationTests+XCTest.swift | 8 +++++--- Tests/QueuerTests/QueuerTests+XCTest.swift | 4 ++-- Tests/QueuerTests/QueuerTests.swift | 1 - Tests/QueuerTests/SchedulerTests+XCTest.swift | 4 ++-- Tests/QueuerTests/SemaphoreTests+XCTest.swift | 4 ++-- .../SynchronousOperationTests+XCTest.swift | 4 ++-- generate_linux_tests.rb | 4 ++-- 9 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index 513ba66..139f74c 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -31,15 +31,6 @@ open class ConcurrentOperation: Operation { /// Operation's execution block. public var executionBlock: ((_ operation: ConcurrentOperation) -> Void)? - /// Creates the Operation with an execution block. - /// - /// - Parameter executionBlock: Execution block. - public init(executionBlock: ((_ operation: ConcurrentOperation) -> Void)? = nil) { - super.init() - - self.executionBlock = executionBlock - } - /// Set the Operation as asynchronous. override open var isAsynchronous: Bool { return true @@ -89,6 +80,15 @@ open class ConcurrentOperation: Operation { /// Specify if the operation should retry another time. private var shouldRetry = true + /// Creates the Operation with an execution block. + /// + /// - Parameter executionBlock: Execution block. + public init(executionBlock: ((_ operation: ConcurrentOperation) -> Void)? = nil) { + super.init() + + self.executionBlock = executionBlock + } + /// Start the Operation. override open func start() { _executing = true diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index e545a75..23b901b 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -2,9 +2,9 @@ // LinuxMain.swift // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift index 8fa163b..d6f4540 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift @@ -2,9 +2,9 @@ // ConcurrentOperationTests+XCTest.swift // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -39,7 +39,9 @@ internal extension ConcurrentOperationTests { ("testInitWithExecutionBlock", testInitWithExecutionBlock), ("testIsAsynchronous", testIsAsynchronous), ("testAddToSharedQueuer", testAddToSharedQueuer), - ("testAddToQueue", testAddToQueue) + ("testAddToQueue", testAddToQueue), + ("testSimpleRetry", testSimpleRetry), + ("testChainedRetry", testChainedRetry) ] } } diff --git a/Tests/QueuerTests/QueuerTests+XCTest.swift b/Tests/QueuerTests/QueuerTests+XCTest.swift index b2fe8d1..bfe5de0 100644 --- a/Tests/QueuerTests/QueuerTests+XCTest.swift +++ b/Tests/QueuerTests/QueuerTests+XCTest.swift @@ -2,9 +2,9 @@ // QueuerTests+XCTest.swift // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Tests/QueuerTests/QueuerTests.swift b/Tests/QueuerTests/QueuerTests.swift index f9e2342..93a8be1 100644 --- a/Tests/QueuerTests/QueuerTests.swift +++ b/Tests/QueuerTests/QueuerTests.swift @@ -28,7 +28,6 @@ import Dispatch @testable import Queuer import XCTest -// swiftlint:disable type_body_length internal class QueuerTests: XCTestCase { internal func testOperationCount() { let queue = Queuer(name: "QueuerTestOperationCount") diff --git a/Tests/QueuerTests/SchedulerTests+XCTest.swift b/Tests/QueuerTests/SchedulerTests+XCTest.swift index 4523b2e..5842cdf 100644 --- a/Tests/QueuerTests/SchedulerTests+XCTest.swift +++ b/Tests/QueuerTests/SchedulerTests+XCTest.swift @@ -2,9 +2,9 @@ // SchedulerTests+XCTest.swift // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Tests/QueuerTests/SemaphoreTests+XCTest.swift b/Tests/QueuerTests/SemaphoreTests+XCTest.swift index e773f9a..9e795ba 100644 --- a/Tests/QueuerTests/SemaphoreTests+XCTest.swift +++ b/Tests/QueuerTests/SemaphoreTests+XCTest.swift @@ -2,9 +2,9 @@ // SemaphoreTests+XCTest.swift // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift index 9bbdaa7..8aa49d0 100644 --- a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift +++ b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift @@ -2,9 +2,9 @@ // SynchronousOperationTests+XCTest.swift // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/generate_linux_tests.rb b/generate_linux_tests.rb index 4e732e8..8727017 100644 --- a/generate_linux_tests.rb +++ b/generate_linux_tests.rb @@ -36,9 +36,9 @@ def header(file_name) // // Queuer // -// The MIT License (MIT) +// MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2018 Fabrizio Brancati // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal From 860d7a888202e1254408eebccfbe342bd387f749 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Thu, 20 Sep 2018 00:16:42 +0200 Subject: [PATCH 30/57] Improving documentation --- Sources/Queuer/ConcurrentOperation.swift | 40 +++++++++++------------ Sources/Queuer/Queuer.swift | 38 ++++++++++----------- Sources/Queuer/Semaphore.swift | 6 ++-- Sources/Queuer/SynchronousOperation.swift | 14 ++++---- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index 139f74c..5774695 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -28,15 +28,15 @@ import Foundation /// It allows asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block. open class ConcurrentOperation: Operation { - /// Operation's execution block. + /// `Operation`'s execution block. public var executionBlock: ((_ operation: ConcurrentOperation) -> Void)? - /// Set the Operation as asynchronous. + /// Set the `Operation` as asynchronous. override open var isAsynchronous: Bool { return true } - /// Set if the Operation is executing. + /// Set if the `Operation` is executing. private var _executing = false { willSet { willChangeValue(forKey: "isExecuting") @@ -46,12 +46,12 @@ open class ConcurrentOperation: Operation { } } - /// Set if the Operation is executing. + /// Set if the `Operation` is executing. override open var isExecuting: Bool { return _executing } - /// Set if the Operation is finished. + /// Set if the `Operation` is finished. private var _finished = false { willSet { willChangeValue(forKey: "isFinished") @@ -61,13 +61,13 @@ open class ConcurrentOperation: Operation { } } - /// Set if the Operation is finished. + /// Set if the `Operation` is finished. override open var isFinished: Bool { return _finished } - /// You should use `hasFailed` if retry is enabled. - /// Set it to `true` if the operation has failed, otherwise `false`. + /// You should use `hasFailed` if you want the retry feature. + /// Set it to `true` if the `Operation` has failed, otherwise `false`. /// Default is `false` to avoid retries. open var hasFailed = false @@ -77,10 +77,10 @@ open class ConcurrentOperation: Operation { /// Current retry tentative. open var currentAttempt = 1 - /// Specify if the operation should retry another time. + /// Specify if the `Operation` should retry another time. private var shouldRetry = true - /// Creates the Operation with an execution block. + /// Creates the `Operation` with an execution block. /// /// - Parameter executionBlock: Execution block. public init(executionBlock: ((_ operation: ConcurrentOperation) -> Void)? = nil) { @@ -89,13 +89,13 @@ open class ConcurrentOperation: Operation { self.executionBlock = executionBlock } - /// Start the Operation. + /// Start the `Operation`. override open func start() { _executing = true execute() } - /// Execute the Operation. + /// Execute the `Operation`. /// If `executionBlock` is set, it will be executed and also `finish()` will be called. open func execute() { if let executionBlock = executionBlock { @@ -106,10 +106,10 @@ open class ConcurrentOperation: Operation { } } - /// Notify the completion of async task and hence the completion of the operation. - /// Must be called when the Operation is finished. + /// Notify the completion of async task and hence the completion of the `Operation`. + /// Must be called when the `Operation` is finished. /// - /// - Parameter hasFailed: Set it to `true` if the operation has failed, otherwise `false`. + /// - Parameter hasFailed: Set it to `true` if the `Operation` has failed, otherwise `false`. open func finish(_ hasFailed: Bool) { if !hasFailed || currentAttempt >= maximumRetries { _executing = false @@ -121,22 +121,22 @@ open class ConcurrentOperation: Operation { } } - /// Pause the current Operation, if it's supported. + /// Pause the current `Operation`, if it's supported. /// Must be overridend by subclass to get a custom pause action. open func pause() {} - /// Resume the current Operation, if it's supported. + /// Resume the current `Operation`, if it's supported. /// Must be overridend by subclass to get a custom resume action. open func resume() {} - /// Adds the Operation to `shared` Queuer. + /// Adds the `Operation` to `shared` Queuer. public func addToSharedQueuer() { Queuer.shared.addOperation(self) } - /// Adds the Operation to the custom queue. + /// Adds the `Operation` to the custom queue. /// - /// - Parameter queue: Custom queue where the Operation will be added. + /// - Parameter queue: Custom queue where the `Operation` will be added. public func addToQueue(_ queue: Queuer) { queue.addOperation(self) } diff --git a/Sources/Queuer/Queuer.swift b/Sources/Queuer/Queuer.swift index 8a7a3df..60aec42 100644 --- a/Sources/Queuer/Queuer.swift +++ b/Sources/Queuer/Queuer.swift @@ -31,20 +31,20 @@ public class Queuer { /// Shared Queuer. public static let shared = Queuer(name: "Queuer") - /// Queuer OperationQueue. + /// Queuer `OperationQueue`. public let queue = OperationQueue() - /// Total Operation count in queue. + /// Total `Operation` count in queue. public var operationCount: Int { return queue.operationCount } - /// Operations currently in queue. + /// `Operation`s currently in queue. public var operations: [Operation] { return queue.operations } - /// The default service level to apply to operations executed using the queue. + /// The default service level to apply to `Operation`s executed using the queue. public var qualityOfService: QualityOfService { get { return queue.qualityOfService @@ -61,7 +61,7 @@ public class Queuer { return !queue.isSuspended } - /// Define the max concurrent operation count. + /// Define the max concurrent `Operation`s count. public var maxConcurrentOperationCount: Int { get { return queue.maxConcurrentOperationCount @@ -75,37 +75,37 @@ public class Queuer { /// /// - Parameters: /// - name: Custom queue name. - /// - maxConcurrentOperationCount: The max concurrent operation count. - /// - qualityOfService: The default service level to apply to operations executed using the queue. + /// - maxConcurrentOperationCount: The max concurrent `Operation`s count. + /// - qualityOfService: The default service level to apply to `Operation`s executed using the queue. public init(name: String, maxConcurrentOperationCount: Int = Int.max, qualityOfService: QualityOfService = .default) { queue.name = name self.maxConcurrentOperationCount = maxConcurrentOperationCount self.qualityOfService = qualityOfService } - /// Add an Operation to be executed asynchronously. + /// Add an `Operation` to be executed asynchronously. /// /// - Parameter block: Block to be executed. public func addOperation(_ operation: @escaping () -> Void) { queue.addOperation(operation) } - /// Add an Operation to be executed asynchronously. + /// Add an `Operation` to be executed asynchronously. /// - /// - Parameter operation: Operation to be executed. + /// - Parameter operation: `Operation` to be executed. public func addOperation(_ operation: Operation) { queue.addOperation(operation) } - /// Add an Array of chained Operations. + /// Add an Array of chained `Operation`s. /// /// Example: /// /// [A, B, C] = A -> B -> C -> completionHandler. /// /// - Parameters: - /// - operations: Operations Array. - /// - completionHandler: Completion block to be exectuted when all Operations + /// - operations: `Operation`s Array. + /// - completionHandler: Completion block to be exectuted when all `Operation`s /// are finished. public func addChainedOperations(_ operations: [Operation], completionHandler: (() -> Void)? = nil) { for (index, operation) in operations.enumerated() { @@ -123,15 +123,15 @@ public class Queuer { addCompletionHandler(completionHandler) } - /// Add an Array of chained Operations. + /// Add an Array of chained `Operation`s. /// /// Example: /// /// [A, B, C] = A -> B -> C -> completionHandler. /// /// - Parameters: - /// - operations: Operations list. - /// - completionHandler: Completion block to be exectuted when all Operations + /// - operations: `Operation`s list. + /// - completionHandler: Completion block to be exectuted when all `Operation`s /// are finished. public func addChainedOperations(_ operations: Operation..., completionHandler: (() -> Void)? = nil) { addChainedOperations(operations, completionHandler: completionHandler) @@ -139,7 +139,7 @@ public class Queuer { /// Add a completion block to the queue. /// - /// - Parameter completionHandler: Completion handler to be executed as last operation. + /// - Parameter completionHandler: Completion handler to be executed as last `Operation`. public func addCompletionHandler(_ completionHandler: @escaping () -> Void) { let completionOperation = BlockOperation(block: completionHandler) if let lastOperation = operations.last { @@ -148,7 +148,7 @@ public class Queuer { addOperation(completionOperation) } - /// Cancel all Operations in queue. + /// Cancel all `Operation`s in queue. public func cancelAll() { queue.cancelAllOperations() } @@ -172,7 +172,7 @@ public class Queuer { } /// Blocks the current thread until all of the receiver’s queued and executing - /// operations finish executing. + /// `Operation`s finish executing. public func waitUntilAllOperationsAreFinished() { queue.waitUntilAllOperationsAreFinished() } diff --git a/Sources/Queuer/Semaphore.swift b/Sources/Queuer/Semaphore.swift index 17722f5..e2e1645 100644 --- a/Sources/Queuer/Semaphore.swift +++ b/Sources/Queuer/Semaphore.swift @@ -27,9 +27,9 @@ import Dispatch import Foundation -/// DispatchSemaphore struct wrapper. +/// `DispatchSemaphore` struct wrapper. public struct Semaphore { - /// Private DispatchSemaphore. + /// Private `DispatchSemaphore`. private let semaphore: DispatchSemaphore /// Creates new counting semaphore with an initial value. @@ -39,7 +39,7 @@ public struct Semaphore { /// to the value. /// /// - Parameter poolSize: The starting value for the semaphore. - /// Passing a value less than zero will cause NULL to be returned. + /// Passing a value less than zero will cause `NULL` to be returned. public init(poolSize: Int = 0) { semaphore = DispatchSemaphore(value: poolSize) } diff --git a/Sources/Queuer/SynchronousOperation.swift b/Sources/Queuer/SynchronousOperation.swift index c9a5b02..6f51c82 100644 --- a/Sources/Queuer/SynchronousOperation.swift +++ b/Sources/Queuer/SynchronousOperation.swift @@ -28,32 +28,32 @@ import Foundation /// It allows synchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block. public class SynchronousOperation: ConcurrentOperation { - /// Private semaphore instance. + /// Private `Semaphore` instance. private let semaphore = Semaphore() - /// Set the Operation as synchronous. + /// Set the `Operation` as synchronous. override public var isAsynchronous: Bool { return false } - /// Notify the completion of async task and hence the completion of the operation. - /// Must be called when the Operation is finished. + /// Notify the completion of async task and hence the completion of the `Operation`. + /// Must be called when the `Operation` is finished. /// - /// - Parameter hasFailed: Set it to `true` if the operation has failed, otherwise `false`. + /// - Parameter hasFailed: Set it to `true` if the `Operation` has failed, otherwise `false`. override public func finish(_ hasFailed: Bool) { super.finish(hasFailed) semaphore.continue() } - /// Advises the operation object that it should stop executing its task. + /// Advises the `Operation` object that it should stop executing its task. override public func cancel() { super.cancel() semaphore.continue() } - /// Execute the Operation. + /// Execute the `Operation`. /// If `executionBlock` is set, it will be executed and also `finish()` will be called. override public func execute() { super.execute() From ecb2f9974a1276fdc04cb8df20780b77e60fd7aa Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Thu, 20 Sep 2018 00:41:25 +0200 Subject: [PATCH 31/57] Improving tests --- .../ConcurrentOperationTests.swift | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 0c8bcfc..8aceb39 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -111,4 +111,33 @@ internal class ConcurrentOperationTests: XCTestCase { XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2]) } } + + internal func testCanceledChainedRetry() { + let queue = Queuer(name: "ConcurrentOperationTestCanceledChainedRetry") + let testExpectation = expectation(description: "Canceled Chained Retry") + var order: [Int] = [] + + let concurrentOperation1 = ConcurrentOperation { operation in + Thread.sleep(forTimeInterval: 1) + order.append(0) + operation.hasFailed = true + } + let concurrentOperation2 = ConcurrentOperation { operation in + operation.cancel() + if operation.isCancelled { + return + } + order.append(1) + operation.hasFailed = true + } + queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { + order.append(2) + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0, 0, 0, 2]) + } + } } From 43b39ac9f38f68a87ddac4e87a34255afe206d37 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Thu, 20 Sep 2018 00:47:09 +0200 Subject: [PATCH 32/57] Improving code --- Sources/Queuer/ConcurrentOperation.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index 5774695..a184005 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -128,7 +128,10 @@ open class ConcurrentOperation: Operation { /// Resume the current `Operation`, if it's supported. /// Must be overridend by subclass to get a custom resume action. open func resume() {} - +} + +/// `ConcurrentOperation` extension with queue handling. +public extension ConcurrentOperation { /// Adds the `Operation` to `shared` Queuer. public func addToSharedQueuer() { Queuer.shared.addOperation(self) From 60ec73cc9850e80f2e8ec444484bef890c1f3709 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Thu, 20 Sep 2018 00:49:26 +0200 Subject: [PATCH 33/57] Improving code --- Sources/Queuer/Queuer.swift | 61 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/Sources/Queuer/Queuer.swift b/Sources/Queuer/Queuer.swift index 60aec42..0f4d151 100644 --- a/Sources/Queuer/Queuer.swift +++ b/Sources/Queuer/Queuer.swift @@ -83,6 +83,38 @@ public class Queuer { self.qualityOfService = qualityOfService } + /// Cancel all `Operation`s in queue. + public func cancelAll() { + queue.cancelAllOperations() + } + + /// Pause the queue. + public func pause() { + queue.isSuspended = true + + for operation in queue.operations where operation is ConcurrentOperation { + (operation as? ConcurrentOperation)?.pause() + } + } + + /// Resume the queue. + public func resume() { + queue.isSuspended = false + + for operation in queue.operations where operation is ConcurrentOperation { + (operation as? ConcurrentOperation)?.resume() + } + } + + /// Blocks the current thread until all of the receiver’s queued and executing + /// `Operation`s finish executing. + public func waitUntilAllOperationsAreFinished() { + queue.waitUntilAllOperationsAreFinished() + } +} + +/// `Queuer` extension with `Operation`s handling. +public extension Queuer { /// Add an `Operation` to be executed asynchronously. /// /// - Parameter block: Block to be executed. @@ -147,33 +179,4 @@ public class Queuer { } addOperation(completionOperation) } - - /// Cancel all `Operation`s in queue. - public func cancelAll() { - queue.cancelAllOperations() - } - - /// Pause the queue. - public func pause() { - queue.isSuspended = true - - for operation in queue.operations where operation is ConcurrentOperation { - (operation as? ConcurrentOperation)?.pause() - } - } - - /// Resume the queue. - public func resume() { - queue.isSuspended = false - - for operation in queue.operations where operation is ConcurrentOperation { - (operation as? ConcurrentOperation)?.resume() - } - } - - /// Blocks the current thread until all of the receiver’s queued and executing - /// `Operation`s finish executing. - public func waitUntilAllOperationsAreFinished() { - queue.waitUntilAllOperationsAreFinished() - } } From 57a68b5c3364ac11b07f6273fc5acce169f3e17a Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 22 Sep 2018 18:34:26 +0200 Subject: [PATCH 34/57] Improving tests --- .../SynchronousOperationTests.swift | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Tests/QueuerTests/SynchronousOperationTests.swift b/Tests/QueuerTests/SynchronousOperationTests.swift index b542a31..6f5d688 100644 --- a/Tests/QueuerTests/SynchronousOperationTests.swift +++ b/Tests/QueuerTests/SynchronousOperationTests.swift @@ -80,6 +80,35 @@ internal class SynchronousOperationTests: XCTestCase { } } + internal func testSynchronousOperationRetry() { + let queue = Queuer(name: "SynchronousOperationTestRetry") + let testExpectation = expectation(description: "Synchronous Operation Retry") + var order: [Int] = [] + + let synchronousOperation1 = SynchronousOperation { operation in + Thread.sleep(forTimeInterval: 1) + order.append(0) + operation.hasFailed = true + + if operation.currentAttempt == 3 { + testExpectation.fulfill() + } + } + let synchronousOperation2 = SynchronousOperation { _ in + order.append(1) + } + synchronousOperation1.addToQueue(queue) + synchronousOperation2.addToQueue(queue) + + XCTAssertFalse(synchronousOperation1.isAsynchronous) + XCTAssertFalse(synchronousOperation2.isAsynchronous) + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [1, 0, 0, 0]) + } + } + internal func testCancel() { let queue = Queuer(name: "SynchronousOperationTestCancel") queue.maxConcurrentOperationCount = 1 From 3ffb15b0d4e6cecb58479a09ba8b55c9122f352e Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sat, 22 Sep 2018 19:27:49 +0200 Subject: [PATCH 35/57] Adding manual retry feature --- Sources/Queuer/ConcurrentOperation.swift | 23 ++++++- .../ConcurrentOperationTests.swift | 60 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index a184005..242fb32 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -72,10 +72,16 @@ open class ConcurrentOperation: Operation { open var hasFailed = false /// Maximum allowed retries. + /// Default are 3 retries. open var maximumRetries = 3 - /// Current retry tentative. - open var currentAttempt = 1 + /// Current retry attempt. + private(set) open var currentAttempt = 1 + + /// Allows for manual retries. + /// If set to `true`, `retry()` function must be manually called. + /// Default is `false` to automatically retry. + open var manualRetry = false /// Specify if the `Operation` should retry another time. private var shouldRetry = true @@ -95,14 +101,25 @@ open class ConcurrentOperation: Operation { execute() } + /// Retry function. + /// It only works if `manualRetry` property has been set to `true`. + open func retry() { + if manualRetry, shouldRetry, let executionBlock = executionBlock { + executionBlock(self) + self.finish(hasFailed) + } + } + /// Execute the `Operation`. /// If `executionBlock` is set, it will be executed and also `finish()` will be called. open func execute() { if let executionBlock = executionBlock { - while shouldRetry { + while shouldRetry, !manualRetry { executionBlock(self) self.finish(hasFailed) } + + retry() } } diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 8aceb39..8b63bcb 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -140,4 +140,64 @@ internal class ConcurrentOperationTests: XCTestCase { XCTAssertEqual(order, [0, 0, 0, 2]) } } + + internal func testChainedManualRetry() { + let queue = Queuer(name: "ConcurrentOperationTestChainedManualRetry") + let testExpectation = expectation(description: "Chained Manual Retry") + var order: [Int] = [] + + let concurrentOperation1 = ConcurrentOperation { operation in + order.append(0) + operation.hasFailed = true + } + concurrentOperation1.manualRetry = true + let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in + concurrentOperation1.retry() + if concurrentOperation1.currentAttempt > concurrentOperation1.maximumRetries { + timer.invalidate() + } + } + + let concurrentOperation2 = ConcurrentOperation { operation in + order.append(1) + operation.hasFailed = true + } + queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { + order.append(2) + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2]) + } + } + + internal func testChainedWrongManualRetry() { + let queue = Queuer(name: "ConcurrentOperationTestChainedWrongManualRetry") + let testExpectation = expectation(description: "Chained Wrong Manual Retry") + var order: [Int] = [] + + let concurrentOperation1 = ConcurrentOperation { operation in + order.append(0) + operation.hasFailed = true + } + concurrentOperation1.manualRetry = true + + let concurrentOperation2 = ConcurrentOperation { operation in + order.append(1) + } + queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { + order.append(2) + } + + let _ = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { timer in + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0]) + } + } } From 8df97eeb67c7e7d7a1c2dcb3fe0b689b7b366c72 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 18:42:36 +0200 Subject: [PATCH 36/57] Improving documentation --- CHANGELOG.md | 19 +++++------ README.md | 58 ++++++++++++++++++++++++++++++---- Sources/Queuer/Semaphore.swift | 3 ++ 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ace826..6130a14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,27 +16,28 @@ All notable changes to this project will be documented in this file.
--- -## Swift 4.2 +## [2.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.0.0) - Let Me Retry +### XX XXX 2018 ### Added - Added support to Xcode 10 and Swift 4.2 -- Added retry feature to `ConcurrentOperation` class [#32](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10) +- Added retry feature to `ConcurrentOperation` class [#32](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10), more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) and [here](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation) - Added `addCompletionHandler(_:)` function to `Queuer` class +- Added a `Scheduler` class to better schedule your tasks + +### Improved +- Improved `Semaphore` with timeout handling +- Updated SwiftLint to 0.27.0 ### Changed -- Changed `executionBlock` of `ConcurrentOperation` to pass the `concurrentOperation` variable inside the closure to be able to use the retry feature. If you don't need it simply put `_ in` after the block creation +- Changed `executionBlock` of `ConcurrentOperation` to pass the `concurrentOperation` variable inside the closure to be able to use the retry feature. If you don't need it simply put `_ in` after the block creation: ```swift let concurrentOperation = ConcurrentOperation { _ in /// Your task here } ``` + This also affects `SynchronousOperation` - Changed from Codecov to Coveralls service for code coverage ---- - -## Develop -### Improved -- Updated SwiftLint to 0.27.0 - ### Removed - Removed Hound CI diff --git a/README.md b/README.md index dfb3fae..815b438 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,18 @@ See [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) sect Usage ===== +- [Shared Queuer](https://github.com/FabrizioBrancati/Queuer#shared-queuer) +- [Custom Queue](https://github.com/FabrizioBrancati/Queuer#custom-queue) +- [Create an Operation Block](https://github.com/FabrizioBrancati/Queuer#create-an-operation-block) +- [Chained Operations](https://github.com/FabrizioBrancati/Queuer#chained-operations) +- [Queue States](https://github.com/FabrizioBrancati/Queuer#queue-states) +- [Asynchronous Operation](https://github.com/FabrizioBrancati/Queuer#anynchronous-operation) +- [Synchronous Operation](https://github.com/FabrizioBrancati/Queuer#synchronous-operation) +- [Automatically Retry an Operation](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) +- [Manually Retry an Operation](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation) +- [Scheduler](https://github.com/FabrizioBrancati/Queuer#scheduler) +- [Semaphore](https://github.com/FabrizioBrancati/Queuer#semaphore) + ### Shared Queuer ```swift @@ -182,7 +194,7 @@ You have three methods to add an `Operation` block: - Creating a `ConcurrentOperation` with a block: ```swift - let concurrentOperation = ConcurrentOperation { + let concurrentOperation = ConcurrentOperation { _ in /// Your task here } queue.addOperation(concurrentOperation) @@ -190,7 +202,7 @@ You have three methods to add an `Operation` block: - Creating a `SynchronousOperation` with a block: ```swift - let synchronousOperation = SynchronousOperation { + let synchronousOperation = SynchronousOperation { _ in /// Your task here } queue.addOperation(concurrentOperation) @@ -202,10 +214,10 @@ You have three methods to add an `Operation` block: Chained Operations are operations that add a dependency each other.
They follow the given array order, for example: `[A, B, C] = A -> B -> C -> completionBlock`. ```swift -let concurrentOperation1 = ConcurrentOperation { +let concurrentOperation1 = ConcurrentOperation { _ in /// Your task 1 here } -let concurrentOperation2 = ConcurrentOperation { +let concurrentOperation2 = ConcurrentOperation { _ in /// Your task 2 here } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { @@ -246,7 +258,7 @@ You must override `execute()` function and call the `finish()` function inside i For convenience it has an `init` function with a completion block: ```swift -let concurrentOperation = ConcurrentOperation { +let concurrentOperation = ConcurrentOperation { _ in /// Your task here } concurrentOperation.addToQueue(queue) @@ -263,12 +275,46 @@ There are three methods to create synchronous tasks or even queue: For convenience it has an `init` function with a completion block: ```swift -let synchronousOperation = SynchronousOperation { +let synchronousOperation = SynchronousOperation { _ in /// Your task here } synchronousOperation.addToQueue(queue) ``` +### Automatically Retry an Operation +An `Operation` is passed to every closure, with it you can set and handle the retry feature.
+By default the retry feature is disabled, to enable it simply set the `hasFailed` property to `true`. With `hasFailed` to `true` the `Operation` will retry until reaches `maximumRetries` property value. To let the `Operation` know when everything is ok, you must set `hasFailed` to `false`.
+With `currentAttempt` you can know at which attempt the `Operation` is. +```swift +let concurrentOperation = ConcurrentOperation { operation in + /// Your task here + if /* Failing */ { + operation.hasFailed = true + } else { + operation.hasFailed = false + } +} +``` + +### Manually Retry an Operation +It's even possible to manually retry an `Operation` when you think that the execution will be successful.
+An `Operation` is passed to every closure, with it you can set and handle the retry feature.
+By default the manual retry feature is disabled, to enable it simply set the `manualRetry` property to `true`, you must do this outside of the execution closure. You must also set `hasFailed` to `true` or `false` to let the `Operation` when is everything ok, like the automatic retry feature.
+To let the `Operation` retry your execution closure, you have to call the `retry()` function. If the `retry()` is not called, you may block the entire queue. Be sure to call it at least `maximumRetries` times, it is not a problem if you call `retry()` more times than is needed, your execution closure will not be executed more times than the `maximumRetries` value. +```swift +let concurrentOperation = ConcurrentOperation { operation in + /// Your task here + if /* Failing */ { + operation.hasFailed = true + } else { + operation.hasFailed = false + } +} +concurrentOperation.manualRetry = true +/// Later on your code +concurrentOperation.retry() +``` + ### Scheduler A `Scheduler` is a struct that uses the GDC's `DispatchSourceTimer` to create a timer that can execute functions with a specified interval and quality of service. diff --git a/Sources/Queuer/Semaphore.swift b/Sources/Queuer/Semaphore.swift index e2e1645..cc9fe31 100644 --- a/Sources/Queuer/Semaphore.swift +++ b/Sources/Queuer/Semaphore.swift @@ -45,6 +45,9 @@ public struct Semaphore { } /// Wait for a `continue` function call. + /// + /// - Parameter timeout: The timeout `DispatchTime`, default is `.distantFuture`. + /// - Returns: Returns a `DispatchTimeoutResult`. @discardableResult public func wait(_ timeout: DispatchTime = .distantFuture) -> DispatchTimeoutResult { return semaphore.wait(timeout: timeout) From 25b733b847798bb81fc6b6bd42b834f8a9c646eb Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 18:42:45 +0200 Subject: [PATCH 37/57] Improving code --- Sources/Queuer/ConcurrentOperation.swift | 2 +- Tests/QueuerTests/ConcurrentOperationTests.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index 242fb32..ddf2d70 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -76,7 +76,7 @@ open class ConcurrentOperation: Operation { open var maximumRetries = 3 /// Current retry attempt. - private(set) open var currentAttempt = 1 + open private(set) var currentAttempt = 1 /// Allows for manual retries. /// If set to `true`, `retry()` function must be manually called. diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 8b63bcb..724c6e6 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -124,7 +124,7 @@ internal class ConcurrentOperationTests: XCTestCase { } let concurrentOperation2 = ConcurrentOperation { operation in operation.cancel() - if operation.isCancelled { + guard !operation.isCancelled else { return } order.append(1) @@ -151,7 +151,7 @@ internal class ConcurrentOperationTests: XCTestCase { operation.hasFailed = true } concurrentOperation1.manualRetry = true - let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in + _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in concurrentOperation1.retry() if concurrentOperation1.currentAttempt > concurrentOperation1.maximumRetries { timer.invalidate() @@ -184,14 +184,14 @@ internal class ConcurrentOperationTests: XCTestCase { } concurrentOperation1.manualRetry = true - let concurrentOperation2 = ConcurrentOperation { operation in + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { order.append(2) } - let _ = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { timer in + _ = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in testExpectation.fulfill() } From 388b34e2dc3d7d8e73c81863f592abe14798cb28 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 18:59:48 +0200 Subject: [PATCH 38/57] Fixing tests --- Tests/QueuerTests/ConcurrentOperationTests.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 724c6e6..11497ae 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -151,11 +151,9 @@ internal class ConcurrentOperationTests: XCTestCase { operation.hasFailed = true } concurrentOperation1.manualRetry = true - _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in + var schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) + schedule.setHandler { concurrentOperation1.retry() - if concurrentOperation1.currentAttempt > concurrentOperation1.maximumRetries { - timer.invalidate() - } } let concurrentOperation2 = ConcurrentOperation { operation in From f0d3d921931b582f8f4103206cd23807cbdee769 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 19:30:45 +0200 Subject: [PATCH 39/57] Fixing tests --- Tests/QueuerTests/ConcurrentOperationTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 11497ae..fea20ae 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -189,8 +189,10 @@ internal class ConcurrentOperationTests: XCTestCase { order.append(2) } - _ = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in + var schedule = Scheduler(deadline: .now(), repeating: .seconds(3)) + schedule.setHandler { testExpectation.fulfill() + schedule.timer.cancel() } waitForExpectations(timeout: 5) { error in From 9a49c7f6bf9400b1477f75716af68bf31a6e00da Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 21:21:55 +0200 Subject: [PATCH 40/57] Fixing tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e411c6..fa5e0d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -90,7 +90,7 @@ script: - if [ "$SPM" == "YES" ]; then swift package clean; ruby generate_linux_tests.rb; - swift test --parallel; + swift test; fi - if [ "$TRAVIS_OS_NAME" == "osx" ]; then From fb55764c8f3686b51a62135e9c6e64a82b64e1cb Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 22:45:07 +0200 Subject: [PATCH 41/57] Fixing tests --- .../ConcurrentOperationTests.swift | 14 ++++--- Tests/QueuerTests/QueuerTests.swift | 3 +- Tests/QueuerTests/SchedulerTests.swift | 37 +++++++++++++++++-- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index fea20ae..0b3b383 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -151,8 +151,14 @@ internal class ConcurrentOperationTests: XCTestCase { operation.hasFailed = true } concurrentOperation1.manualRetry = true - var schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) - schedule.setHandler { + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { + concurrentOperation1.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { + concurrentOperation1.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { concurrentOperation1.retry() } @@ -189,10 +195,8 @@ internal class ConcurrentOperationTests: XCTestCase { order.append(2) } - var schedule = Scheduler(deadline: .now(), repeating: .seconds(3)) - schedule.setHandler { + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { testExpectation.fulfill() - schedule.timer.cancel() } waitForExpectations(timeout: 5) { error in diff --git a/Tests/QueuerTests/QueuerTests.swift b/Tests/QueuerTests/QueuerTests.swift index 93a8be1..d9181a8 100644 --- a/Tests/QueuerTests/QueuerTests.swift +++ b/Tests/QueuerTests/QueuerTests.swift @@ -143,8 +143,7 @@ internal class QueuerTests: XCTestCase { queue.addOperation(concurrentOperation1) queue.addOperation(concurrentOperation2) - let deadline = DispatchTime.now() + .seconds(2) - DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) { + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { testExpectation.fulfill() } diff --git a/Tests/QueuerTests/SchedulerTests.swift b/Tests/QueuerTests/SchedulerTests.swift index ddbc1ce..395e8c8 100644 --- a/Tests/QueuerTests/SchedulerTests.swift +++ b/Tests/QueuerTests/SchedulerTests.swift @@ -31,28 +31,59 @@ import XCTest internal class SchedulerTests: XCTestCase { internal func testInitWithoutHandler() { let testExpectation = expectation(description: "Init Without Handler") + var order: [Int] = [] var schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) schedule.setHandler { + order.append(0) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(3500)) { testExpectation.fulfill() - schedule.timer.cancel() } - waitForExpectations(timeout: 2) { error in + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) + XCTAssertEqual(order, [0 ,0 ,0, 0]) } } internal func testInitWithHandler() { let testExpectation = expectation(description: "Init With Handler") + var order: [Int] = [] let schedule = Scheduler(deadline: .now(), repeating: .never) { + order.append(0) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(3500)) { testExpectation.fulfill() } - waitForExpectations(timeout: 2) { error in + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) + XCTAssertEqual(order, [0]) schedule.timer.cancel() } } + + internal func testCancel() { + let testExpectation = expectation(description: "Init Without Handler") + var order: [Int] = [] + + var schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) + schedule.setHandler { + order.append(0) + schedule.timer.cancel() + } + + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(3500)) { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0]) + } + } } From c49891153baaa03760da1b109a008a33192e9826 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 23 Sep 2018 23:11:12 +0200 Subject: [PATCH 42/57] Fixing tests --- Tests/QueuerTests/ConcurrentOperationTests.swift | 2 +- Tests/QueuerTests/QueuerTests.swift | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 0b3b383..5ea45d9 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -75,10 +75,10 @@ internal class ConcurrentOperationTests: XCTestCase { let concurrentOperation = ConcurrentOperation { operation in operation.hasFailed = true } - concurrentOperation.addToQueue(queue) queue.addCompletionHandler { testExpectation.fulfill() } + concurrentOperation.addToQueue(queue) waitForExpectations(timeout: 5) { error in XCTAssertNil(error) diff --git a/Tests/QueuerTests/QueuerTests.swift b/Tests/QueuerTests/QueuerTests.swift index d9181a8..7976beb 100644 --- a/Tests/QueuerTests/QueuerTests.swift +++ b/Tests/QueuerTests/QueuerTests.swift @@ -109,7 +109,6 @@ internal class QueuerTests: XCTestCase { waitForExpectations(timeout: 5) { error in XCTAssertNil(error) - XCTAssertEqual(queue.operationCount, 0) } } From 421d395837c7e7c23a3f264c7796479d53100abb Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 24 Sep 2018 00:00:40 +0200 Subject: [PATCH 43/57] Improving README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 815b438..bd42236 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Features ======== Queuer is a queue manager, built on top of [OperationQueue](https://developer.apple.com/documentation/foundation/operationqueue) and [Dispatch](https://developer.apple.com/documentation/dispatch) (aka GCD).
-It allows you to create any synchronous and asynchronous task easily, with just a few lines. +It allows you to create any asynchronous and synchronous task easily, all managed by a queue, with just a few lines. Here is the list of all the features: - [x] Works on all Swift compatible platforms (even Linux) @@ -50,6 +50,7 @@ Here is the list of all the features: - [x] Declare how many concurrent operation a queue can handle - [x] Create semaphores - [x] Create and handle schedules +- [x] Automatically or manually retry an operation - [ ] Ability to restore uncompleted operations Requirements @@ -60,7 +61,7 @@ Requirements | 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | | 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | | 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | -| 4.2 | 10.0 | 2.x.x | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | +| 4.2 | 10.0 | 2.0.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | Installing ========== From a3c29afa1ff1af019144e1f54e77d407f713448a Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 24 Sep 2018 00:00:56 +0200 Subject: [PATCH 44/57] Improving README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bd42236..da34860 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Here is the list of all the features: - [x] Create and handle schedules - [x] Automatically or manually retry an operation - [ ] Ability to restore uncompleted operations +- [ ] Add throlling between each automatic operation retry Requirements ============ From 4f30c30f2eee95adae8f590a0f66d11afd77ed0c Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 24 Sep 2018 00:11:03 +0200 Subject: [PATCH 45/57] Bumping version to 2.0.0 --- CHANGELOG.md | 3 +++ Queuer.podspec | 2 +- Queuer.xcodeproj/project.pbxproj | 4 ++-- Sources/Info-iOS.plist | 2 +- Sources/Info-macOS.plist | 2 +- Sources/Info-tvOS.plist | 2 +- Sources/Info-watchOS.plist | 2 +- Tests/Info.plist | 2 +- jazzy.sh | 2 +- 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6130a14..f629e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file.
--- +### 2.x Releases +- `2.0.x` Releases - [2.0.0](#200---let-me-retry) + ### 1.x Releases - `1.3.x` Releases - [1.3.0](#130---open-everything) | [1.3.1](#131---swift-41-support) | [1.3.2](#132---linux-quality) - `1.2.x` Releases - [1.2.0](#120---swift-4-support) | [1.2.1](#121---unwanted-alert) diff --git a/Queuer.podspec b/Queuer.podspec index d9eefa3..8d6be88 100644 --- a/Queuer.podspec +++ b/Queuer.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'Queuer' s.module_name = 'Queuer' - s.version = '1.3.2' + s.version = '2.0.0' s.summary = 'Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD).' s.homepage = 'https://github.com/FabrizioBrancati/Queuer' s.screenshots = 'https://github.fabriziobrancati.com/queuer/resources/queuer-screenshot.png' diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index fdac045..8465193 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -732,7 +732,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.3.2; + CURRENT_PROJECT_VERSION = 2.0.0; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -813,7 +813,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.3.2; + CURRENT_PROJECT_VERSION = 2.0.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; diff --git a/Sources/Info-iOS.plist b/Sources/Info-iOS.plist index 2a3d8ce..d87c8b3 100644 --- a/Sources/Info-iOS.plist +++ b/Sources/Info-iOS.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.3.2 + 2.0.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/Sources/Info-macOS.plist b/Sources/Info-macOS.plist index 0d1adf9..ae553b9 100644 --- a/Sources/Info-macOS.plist +++ b/Sources/Info-macOS.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.3.2 + 2.0.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright diff --git a/Sources/Info-tvOS.plist b/Sources/Info-tvOS.plist index 0fb03af..267478e 100644 --- a/Sources/Info-tvOS.plist +++ b/Sources/Info-tvOS.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.3.2 + 2.0.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/Sources/Info-watchOS.plist b/Sources/Info-watchOS.plist index 2a3d8ce..d87c8b3 100644 --- a/Sources/Info-watchOS.plist +++ b/Sources/Info-watchOS.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.3.2 + 2.0.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/Tests/Info.plist b/Tests/Info.plist index df52bb5..60e89d2 100644 --- a/Tests/Info.plist +++ b/Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.2 + 2.0.0 CFBundleVersion 1 diff --git a/jazzy.sh b/jazzy.sh index e49fa0d..c384069 100755 --- a/jazzy.sh +++ b/jazzy.sh @@ -2,7 +2,7 @@ # Creates documentation using Jazzy. -FRAMEWORK_VERSION=1.3.2 +FRAMEWORK_VERSION=2.0.0 jazzy \ --clean \ From 7bf6e74e0f2aa0b40a2b95339b4e0bf1b3834edf Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 24 Sep 2018 00:29:04 +0200 Subject: [PATCH 46/57] Updating README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index da34860..d010b51 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ [![Version](https://img.shields.io/cocoapods/v/Queuer.svg?style=flat)][Documentation] [![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://github.com/FabrizioBrancati/Queuer/blob/master/LICENSE)
-[![Language](https://img.shields.io/badge/language-Swift%204.0%20%7C%204.1-orange.svg)](https://swift.org/) -[![Platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-ffc713.svg)][Documentation] +[![Language](https://img.shields.io/badge/language-Swift%204.2-orange.svg)](https://swift.org/) +[![Platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-cc9c00.svg)][Documentation] --- From 678860443a3253518ce9c5ffc775d6b9cf6c7368 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 24 Sep 2018 00:29:14 +0200 Subject: [PATCH 47/57] Adding missing tests --- Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift | 5 ++++- Tests/QueuerTests/SchedulerTests+XCTest.swift | 3 ++- Tests/QueuerTests/SynchronousOperationTests+XCTest.swift | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift index d6f4540..b4025d9 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift @@ -41,7 +41,10 @@ internal extension ConcurrentOperationTests { ("testAddToSharedQueuer", testAddToSharedQueuer), ("testAddToQueue", testAddToQueue), ("testSimpleRetry", testSimpleRetry), - ("testChainedRetry", testChainedRetry) + ("testChainedRetry", testChainedRetry), + ("testCanceledChainedRetry", testCanceledChainedRetry), + ("testChainedManualRetry", testChainedManualRetry), + ("testChainedWrongManualRetry", testChainedWrongManualRetry) ] } } diff --git a/Tests/QueuerTests/SchedulerTests+XCTest.swift b/Tests/QueuerTests/SchedulerTests+XCTest.swift index 5842cdf..c893436 100644 --- a/Tests/QueuerTests/SchedulerTests+XCTest.swift +++ b/Tests/QueuerTests/SchedulerTests+XCTest.swift @@ -37,7 +37,8 @@ internal extension SchedulerTests { internal static var allTests: [(String, (SchedulerTests) -> () throws -> Void)] { return [ ("testInitWithoutHandler", testInitWithoutHandler), - ("testInitWithHandler", testInitWithHandler) + ("testInitWithHandler", testInitWithHandler), + ("testCancel", testCancel) ] } } diff --git a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift index 8aa49d0..e8a4e19 100644 --- a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift +++ b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift @@ -38,6 +38,7 @@ internal extension SynchronousOperationTests { return [ ("testSynchronousOperation", testSynchronousOperation), ("testSynchronousOperationOnSharedQueuer", testSynchronousOperationOnSharedQueuer), + ("testSynchronousOperationRetry", testSynchronousOperationRetry), ("testCancel", testCancel) ] } From 283f71b9ff8769142b08f72a6293fce26db8c2a6 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 14 Oct 2018 23:59:46 +0200 Subject: [PATCH 48/57] Minor change --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f629e26..900585a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ All notable changes to this project will be documented in this file.
--- ## [2.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.0.0) - Let Me Retry -### XX XXX 2018 +### 2018 ### Added - Added support to Xcode 10 and Swift 4.2 - Added retry feature to `ConcurrentOperation` class [#32](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10), more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) and [here](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation) From 03027dc4c40fc06847d92862f8f63a0b72e3f46a Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 15 Oct 2018 00:43:01 +0200 Subject: [PATCH 49/57] Minor change --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 900585a..f629e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ All notable changes to this project will be documented in this file.
--- ## [2.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.0.0) - Let Me Retry -### 2018 +### XX XXX 2018 ### Added - Added support to Xcode 10 and Swift 4.2 - Added retry feature to `ConcurrentOperation` class [#32](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10), more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) and [here](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation) From 09b09777a660e0019bfced4eb1ae26a353664de4 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Tue, 16 Oct 2018 00:23:15 +0200 Subject: [PATCH 50/57] Improving project --- Queuer.xcodeproj/project.pbxproj | 26 +++++++++------------- Sources/Info-iOS.plist | 24 -------------------- Sources/Info-tvOS.plist | 28 ------------------------ Sources/Info-watchOS.plist | 24 -------------------- Sources/{Info-macOS.plist => Info.plist} | 4 ++++ 5 files changed, 14 insertions(+), 92 deletions(-) delete mode 100644 Sources/Info-iOS.plist delete mode 100644 Sources/Info-tvOS.plist delete mode 100644 Sources/Info-watchOS.plist rename Sources/{Info-macOS.plist => Info.plist} (90%) diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index 8465193..c61aa1d 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -90,10 +90,7 @@ 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueuerTests.swift; sourceTree = ""; }; 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemaphoreTests.swift; sourceTree = ""; }; 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousOperationTests.swift; sourceTree = ""; }; - 49C7BCB61F26938F00F4FFBC /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; - 49C7BCB71F26938F00F4FFBC /* Info-macOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; - 49C7BCB81F26938F00F4FFBC /* Info-tvOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; - 49C7BCB91F26938F00F4FFBC /* Info-watchOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-watchOS.plist"; sourceTree = ""; }; + 49C7BCB71F26938F00F4FFBC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentOperation.swift; sourceTree = ""; }; 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queuer.swift; sourceTree = ""; }; 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Semaphore.swift; sourceTree = ""; }; @@ -204,10 +201,7 @@ 49C7BCB51F26938F00F4FFBC /* Sources */ = { isa = PBXGroup; children = ( - 49C7BCB61F26938F00F4FFBC /* Info-iOS.plist */, - 49C7BCB71F26938F00F4FFBC /* Info-macOS.plist */, - 49C7BCB81F26938F00F4FFBC /* Info-tvOS.plist */, - 49C7BCB91F26938F00F4FFBC /* Info-watchOS.plist */, + 49C7BCB71F26938F00F4FFBC /* Info.plist */, 49C7BCBA1F26938F00F4FFBC /* Queuer */, 49C7BCC11F26938F00F4FFBC /* Queuer.h */, ); @@ -629,7 +623,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-macOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; @@ -651,7 +645,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-macOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; @@ -859,7 +853,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-iOS"; @@ -879,7 +873,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-iOS"; @@ -931,7 +925,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-watchOS"; @@ -953,7 +947,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-watchOS"; @@ -975,7 +969,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-tvOS"; @@ -997,7 +991,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist"; + INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-tvOS"; diff --git a/Sources/Info-iOS.plist b/Sources/Info-iOS.plist deleted file mode 100644 index d87c8b3..0000000 --- a/Sources/Info-iOS.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 2.0.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/Info-tvOS.plist b/Sources/Info-tvOS.plist deleted file mode 100644 index 267478e..0000000 --- a/Sources/Info-tvOS.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 2.0.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - UIRequiredDeviceCapabilities - - arm64 - - - diff --git a/Sources/Info-watchOS.plist b/Sources/Info-watchOS.plist deleted file mode 100644 index d87c8b3..0000000 --- a/Sources/Info-watchOS.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 2.0.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/Info-macOS.plist b/Sources/Info.plist similarity index 90% rename from Sources/Info-macOS.plist rename to Sources/Info.plist index ae553b9..73dbae2 100644 --- a/Sources/Info-macOS.plist +++ b/Sources/Info.plist @@ -22,5 +22,9 @@ Copyright © 2017 - 2018 Fabrizio Brancati. NSPrincipalClass + UIRequiredDeviceCapabilities + + arm64 + From 7976a04490d43031f7c6a9cc26a1a3ae62e4f996 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Tue, 16 Oct 2018 00:33:19 +0200 Subject: [PATCH 51/57] Adding missing platforms --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fa5e0d8..f8bbe1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,10 @@ matrix: language: objective-c osx_image: xcode9.2 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" + - os: osx + language: objective-c + osx_image: xcode10 + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 @@ -51,7 +55,11 @@ matrix: - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=5.0,name=Apple Watch Series 4 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" + - os: osx + language: objective-c + osx_image: xcode10 + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=4.2,name=Apple Watch Series 3 - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 From 17c6171b8b8f8a0ca9b8f78d4213676d6afe41c4 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Tue, 16 Oct 2018 07:48:56 +0200 Subject: [PATCH 52/57] Fixing build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f8bbe1c..89f180f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ matrix: - os: osx language: objective-c osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=5.0,name=Apple Watch Series 4 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" + env: PROJ="Queuer.xcodeproj" DESTINATION="OS=5.0,name=Apple Watch Series 4 - 44mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 From ec40d6d7b967c4ab38540ca2d7849d12e8fc450b Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 21 Oct 2018 23:20:10 +0200 Subject: [PATCH 53/57] Fixes #11 --- Queuer.podspec | 2 +- Queuer.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Queuer.podspec b/Queuer.podspec index 8d6be88..eb86c90 100644 --- a/Queuer.podspec +++ b/Queuer.podspec @@ -18,5 +18,5 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.0' - s.watchos.deployment_target = '2.0' + s.watchos.deployment_target = '3.0' end diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj index c61aa1d..40dce84 100644 --- a/Queuer.xcodeproj/project.pbxproj +++ b/Queuer.xcodeproj/project.pbxproj @@ -933,7 +933,7 @@ SDKROOT = watchos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; + WATCHOS_DEPLOYMENT_TARGET = 3.0; }; name = Debug; }; @@ -955,7 +955,7 @@ SDKROOT = watchos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; + WATCHOS_DEPLOYMENT_TARGET = 3.0; }; name = Release; }; From f15a86114eb0d01ca1dc78382e501aba6e6d95e5 Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 21 Oct 2018 23:20:24 +0200 Subject: [PATCH 54/57] Removing watchOS 2.0 --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 89f180f..1e63593 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,10 +64,6 @@ matrix: language: objective-c osx_image: xcode10 env: PROJ="Queuer.xcodeproj" DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - - os: osx - language: objective-c - osx_image: xcode10 - env: PROJ="Queuer.xcodeproj" DESTINATION="OS=2.0,name=Apple Watch - 38mm" SCHEME="$WATCHOS_SCHEME" RUN_TESTS="NO" LINT="NO" COVERAGE="NO" - os: osx language: objective-c osx_image: xcode10 From 26a6634a26dd1937ceaa818791db2f8030ca145d Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Sun, 21 Oct 2018 23:20:37 +0200 Subject: [PATCH 55/57] Updating documentation --- CHANGELOG.md | 5 ++++- README.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f629e26..a84f13e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ All notable changes to this project will be documented in this file.
### XX XXX 2018 ### Added - Added support to Xcode 10 and Swift 4.2 -- Added retry feature to `ConcurrentOperation` class [#32](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10), more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) and [here](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation) +- Added retry feature to `ConcurrentOperation` class [#10](https://github.com/FabrizioBrancati/BFKit-Swift/issues/10), more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#automatically-retry-an-operation) and [here](https://github.com/FabrizioBrancati/Queuer#manually-retry-an-operation) - Added `addCompletionHandler(_:)` function to `Queuer` class - Added a `Scheduler` class to better schedule your tasks @@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file.
- Updated SwiftLint to 0.27.0 ### Changed +- Changed watchOS target to watchOS 3.0 instead of 2.0, thanks to an App Store submission rule [#11](https://github.com/FabrizioBrancati/BFKit-Swift/issues/11) - Changed `executionBlock` of `ConcurrentOperation` to pass the `concurrentOperation` variable inside the closure to be able to use the retry feature. If you don't need it simply put `_ in` after the block creation: ```swift let concurrentOperation = ConcurrentOperation { _ in @@ -44,6 +45,8 @@ All notable changes to this project will be documented in this file.
### Removed - Removed Hound CI +Thanks to [@zykloman](https://github.com/zykloman) and [@debjitk](https://github.com/debjitk) for this release + --- ## [1.3.2](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.3.2) - Linux Quality diff --git a/README.md b/README.md index d010b51..bbaa1e3 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Requirements | 3.1...3.2 | 8.3...9.0 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | | 4.0 | 9.0...9.2 | 1.3.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | | 4.1 | 9.3...9.4 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | -| 4.2 | 10.0 | 2.0.0 | 8.0+ | 10.10+ | 9.0+ | 2.0+ | ![✓] | +| 4.2 | 10.0 | 2.0.0 | 8.0+ | 10.10+ | 9.0+ | 3.0+ | ![✓] | Installing ========== From f206ae107af1e1126ddfd4d3f02170d3b3e49acb Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Mon, 22 Oct 2018 00:20:48 +0200 Subject: [PATCH 56/57] Minor changes --- CHANGELOG.md | 8 ++++---- Sources/Queuer/ConcurrentOperation.swift | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84f13e..c3d7b34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,10 +27,6 @@ All notable changes to this project will be documented in this file.
- Added `addCompletionHandler(_:)` function to `Queuer` class - Added a `Scheduler` class to better schedule your tasks -### Improved -- Improved `Semaphore` with timeout handling -- Updated SwiftLint to 0.27.0 - ### Changed - Changed watchOS target to watchOS 3.0 instead of 2.0, thanks to an App Store submission rule [#11](https://github.com/FabrizioBrancati/BFKit-Swift/issues/11) - Changed `executionBlock` of `ConcurrentOperation` to pass the `concurrentOperation` variable inside the closure to be able to use the retry feature. If you don't need it simply put `_ in` after the block creation: @@ -42,6 +38,10 @@ All notable changes to this project will be documented in this file.
This also affects `SynchronousOperation` - Changed from Codecov to Coveralls service for code coverage +### Improved +- Improved `Semaphore` with timeout handling +- Updated SwiftLint to 0.27.0 + ### Removed - Removed Hound CI diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index ddf2d70..e63a761 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -26,7 +26,8 @@ import Foundation -/// It allows asynchronous tasks, has a pause and resume states, can be easily added to a queue and can be created with a block. +/// It allows asynchronous tasks, has a pause and resume states, +/// can be easily added to a queue and can be created with a block. open class ConcurrentOperation: Operation { /// `Operation`'s execution block. public var executionBlock: ((_ operation: ConcurrentOperation) -> Void)? From 83b28f3beeeb6eec507455be998e5829a846667d Mon Sep 17 00:00:00 2001 From: Fabrizio Brancati Date: Tue, 23 Oct 2018 00:41:04 +0200 Subject: [PATCH 57/57] Minor changes --- README.md | 2 +- Sources/Queuer/ConcurrentOperation.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bbaa1e3..4b9e05c 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Here is the list of all the features: - [x] Create and handle schedules - [x] Automatically or manually retry an operation - [ ] Ability to restore uncompleted operations -- [ ] Add throlling between each automatic operation retry +- [ ] Throlling between each automatic operation retry Requirements ============ diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index e63a761..db1cc2f 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -107,7 +107,7 @@ open class ConcurrentOperation: Operation { open func retry() { if manualRetry, shouldRetry, let executionBlock = executionBlock { executionBlock(self) - self.finish(hasFailed) + finish(hasFailed) } } @@ -117,7 +117,7 @@ open class ConcurrentOperation: Operation { if let executionBlock = executionBlock { while shouldRetry, !manualRetry { executionBlock(self) - self.finish(hasFailed) + finish(hasFailed) } retry()