diff --git a/.codebeatsettings b/.codebeatsettings deleted file mode 100644 index eae8d0b..0000000 --- a/.codebeatsettings +++ /dev/null @@ -1,7 +0,0 @@ -{ - "SWIFT": { - "ARITY": [10, 15, 20, 25], - "TOO_MANY_IVARS": [12, 14, 16, 20], - "BLOCK_NESTING": [4, 5, 6, 7] - } -} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 74c7552..8953ec6 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,21 +1,60 @@ -Contributing -============ +# Contributing + I'd love to see your ideas for improving this project. -## Pull requests +## Pull Requests + The best way to contribute is by submitting a pull request. I'll do my best to respond to you as soon as possible. +Remember to open the pull request against the `develop` branch. ## Issues + If you find a bug or you have a suggestion create an issue. -#### Comment everything +## Comments + Every line of the project must to be commented. -#### Writing code -Please follow [Ray Wenderlich - Swift Style Guide](https://github.com/raywenderlich/swift-style-guide#correctness) codestyle. Comment every public methods, properties, classes. Make commits as atomic as possible with understandable comment. If you are developing feature or fixing a bug, please mention the issue number (e.g. #1) in commit text. -Use ```MARK``` to separate each section type. -Example: Global variables, Global functions, Class variables, Instance variables, Class functions, Instance functions & Init functions. +## Writing code + +New API should follow the rules documented in Swift's [API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/). Comment every public methods, properties, classes. Make commits as atomic as possible with understandable comment. If you are developing feature or fixing a bug, please mention the issue number (e.g. #1) in commit text. + +## Changelog + +Once your changes are ready, please add an entry to the [CHANGELOG.md](https://github.com/FabrizioBrancati/Queuer/blob/main/CHANGELOG.md) file. + +## Tests -#### Test everything Add tests for every added function. The aim is to have 100% of code coverage. + +## Linux + +This library supports Linux, so please be sure that the feature that you are adding is compatible with it. If not, due to platform limitations, please wrap the code with `#if !os(Linux)` + +### Using Docker on macOS to Test for Linux + +The easiest way to test this package on Linux is to use Docker. You can use the following steps to set up a Docker container that runs the Swift compiler and test suite: + +1. Install [Docker Desktop for Mac](https://www.docker.com/products/docker-desktop). + +2. Run the following command from the root of this repository to build the + Docker image: + + ```bash + docker run --rm --privileged --interactive --tty \ + --volume "$(pwd):/src" \ + --workdir "/src" \ + swift:5.10 + ``` + +> [!TIP] +> Use `swift:5.10` to use a specific Swift version. If you want to use the latest version, you can use `swift:latest`. +> +> Use `swift:5.10-jammy` to use the Swift 5.10 version with Ubuntu 22.04 and `swift:5.10-focal` to use the Swift 5.10 version with Ubuntu 20.04. + +1. Run the following command to run the test suite: + + ```bash + swift test + ``` diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..082847f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: '' +labels: 'bug' +assignees: '' + +--- + +**Describe the Bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to ... +2. Click on ... +3. Scroll down to ... +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Configuration** +OS and Version: [e.g. iOS 17.4] +Queuer Version: [e.g. 3.0.0] + +**Additional Context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..7d2e4de --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: '' +labels: 'feature' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when ... + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5393756 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + # Maintain dependencies for Swift packages + - package-ecosystem: "swift" + directory: "/" + schedule: + interval: "weekly" + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..81036f4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ +## Summary + +_Provide a description of what your PR addresses, explaining the expected user experience. Also, provide an overview of your implementation._ + +## Support + +_Describe the platforms that your PR supports. If your PR does not support a platform, provide a reason. + +- [ ] iOS +- [ ] macOS +- [ ] macCatalyst +- [ ] tvOS +- [ ] watchOS +- [ ] visionOS +- [ ] Linux + +## Checklist + +Make sure you check off the following items. If they cannot be completed, provide a reason. + +- [ ] Added tests +- [ ] Added documentation +- [ ] Added a changelog entry +- [ ] Added to the README the new functionality description diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..ec8b360 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,60 @@ +name: Tests + +on: + - push + - pull_request + - workflow_dispatch + +jobs: + linux: + strategy: + fail-fast: false + matrix: + swift: + - image: "swift:5.10-jammy" + os: ubuntu-22.04 + - image: "swift:5.9-jammy" + os: ubuntu-22.04 + - image: "swift:5.10-focal" + os: ubuntu-20.04 + - image: "swift:5.9-focal" + os: ubuntu-20.04 + name: Linux + runs-on: ${{ matrix.swift.os }} + container: + image: ${{ matrix.swift.image }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Swift Version + run: swift --version + - name: Debug Build + run: swift build -v -c debug + - name: Debug Test + run: swift test -c debug --parallel + + macos: + strategy: + matrix: + xcode: + - 15.3 + - 15.2 + - 15.1 + - 15.0.1 + name: macOS + runs-on: macos-14 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Select Xcode + run: xcodes select ${{ matrix.xcode }} + - name: Swift Version + run: swift --version + - name: Debug Build + run: swift build -v -c debug + - name: Debug Test for Commit + if: github.event_name != 'pull_request' + run: swift test -c debug --parallel 2>&1 + - name: Debug Test for Pull Request + if: github.event_name == 'pull_request' + run: swift test -c debug --parallel 2>&1 | xcbeautify --renderer github-actions diff --git a/.gitignore b/.gitignore index 8d450af..de7c2bc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,66 @@ -# Swift Package Manager -Packages/ -Package.pins -.build/ +# Created by https://www.toptal.com/developers/gitignore/api/swiftpackagemanager,xcode,macos +# Edit at https://www.toptal.com/developers/gitignore?templates=swiftpackagemanager,xcode,macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud -# Xcode -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 +### SwiftPackageManager ### +Packages +.build/ xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -timeline.xctimeline -playground.xcworkspace - -# Carthage -Carthage/ -Cartfile.resolved - -# Build -build/ DerivedData/ +*.xcodeproj + + +### Xcode ### +## User settings +xcuserdata/ + +## Xcode 8 and earlier +*.xcscmblueprint +*.xccheckout + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.toptal.com/developers/gitignore/api/swiftpackagemanager,xcode,macos -# Jazzy -Docs/ +### Custom ### +.swiftpm +.build diff --git a/.slather.yml b/.slather.yml deleted file mode 100644 index 4cf7de0..0000000 --- a/.slather.yml +++ /dev/null @@ -1,5 +0,0 @@ -coverage_service: coveralls -xcodeproj: Queuer.xcodeproj -scheme: Queuer iOS -ignore: - - Tests/* diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 0000000..2f43a36 --- /dev/null +++ b/.spi.yml @@ -0,0 +1,4 @@ +version: 1 +builder: + configs: + - documentation_targets: [Queuer] \ No newline at end of file diff --git a/.swift-version b/.swift-version deleted file mode 100644 index a75b92f..0000000 --- a/.swift-version +++ /dev/null @@ -1 +0,0 @@ -5.1 diff --git a/.swiftlint.yml b/.swiftlint.yml deleted file mode 100644 index d299b75..0000000 --- a/.swiftlint.yml +++ /dev/null @@ -1,223 +0,0 @@ -included: - - Sources - - Tests - -opt_in_rules: - - anyobject_protocol - - array_init - - attributes - - closure_end_indentation - - closure_spacing - - conditional_returns_on_newline - - contains_over_filter_count - - contains_over_filter_is_empty - - contains_over_first_not_nil - - convenience_type - - empty_collection_literal - - empty_count - - empty_string - - empty_xctest_method - - explicit_acl - - explicit_init - - fallthrough - - fatal_error_message - - file_name - - file_header - - file_types_order - - first_where - - force_unwrapping - - implicitly_unwrapped_optional - - joined_default_parameter - - last_where - - legacy_multiple - - let_var_whitespace - - literal_expression_end_indentation - - lower_acl_than_parent - - mark - - missing_docs - - modifier_order - - multiline_arguments - - multiline_arguments_brackets - - multiline_function_chains - - multiline_literal_brackets - - multiline_parameters - - multiline_parameters_brackets - - nimble_operator - - no_fallthrough_only - - number_separator - - object_literal - - operator_usage_whitespace - - overridden_super_call - - override_in_extension - - pattern_matching_keywords - - private_action - - private_outlet - - prohibited_super_call - - quick_discouraged_call - - quick_discouraged_focused_test - - quick_discouraged_pending_test - - reduce_into - - redundant_nil_coalescing - - single_test_class - - sorted_first_last - - sorted_imports - - switch_case_on_newline - - trailing_closure - - unavailable_function - - unneeded_parentheses_in_closure_argument - - unowned_variable_capture - - untyped_error_in_catch - - vertical_parameter_alignment_on_call - - vertical_whitespace_between_cases - - vertical_whitespace_closing_braces - - vertical_whitespace_opening_braces - - yoda_condition - -disabled_rules: - - trailing_whitespace - - line_length - - file_length - -identifier_name: - excluded: - - id -number_separator: - minimum_length: 5 -file_header: - required_pattern: | - \/\/ - \/\/ SWIFTLINT_CURRENT_FILENAME - \/\/ Queuer - \/\/ - \/\/ MIT License - \/\/ - \/\/ Copyright \(c\) 2017 - 2019 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\. - -custom_rules: - comments_space: - included: ".*.swift" - name: "Space After Comment" - regex: "(^ *//\\w+)" - message: "There should be a space after //" - severity: warning - double_space: - include: "*.swift" - name: "Double space" - regex: "([a-z,A-Z] \\s+)" - message: "Double space between keywords" - match_kinds: keyword - severity: warning - empty_line_after_guard: - included: ".*.swift" - name: "Empty Line After Guard" - regex: "(^ *guard[ a-zA-Z0-9=?.\\(\\),> [!NOTE] +> All notable changes to this project will be documented in this file. +> +> `Queuer` adheres to [Semantic Versioning](http://semver.org/). -All notable changes to this project will be documented in this file.
-`Queuer` adheres to [Semantic Versioning](http://semver.org/). +## 3.x Releases ---- +- `3.0.x` Releases - [3.0.0](#300---the-phoenix) -### 2.x Releases -- `2.1.x` Releases - [2.1.0](#210---swift-50-support) | [2.0.1](#211---swift-51-support) +## 2.x Releases + +- `2.1.x` Releases - [2.1.0](#210---swift-50-support) | [2.1.1](#211---swift-51-support) - `2.0.x` Releases - [2.0.0](#200---let-me-retry) | [2.0.1](#201---better-apis) -### 1.x Releases +## 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) - `1.1.x` Releases - [1.1.0](#110---quality-of-service) - `1.0.x` Releases - [1.0.0](#100---first-queue) ---- +## [3.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/3.0.0) - The Phoenix + +### 24 Apr 2024 + +> [!WARNING] +> The goal of this release is to make the repo more maintainable. +> To do so, only Swift Package Manager will be supported. +> If you rely on any of the removed dependencies managers, like CocoaPods or Carthage, please stick to the previous version. +> +> Queuer 2.1.1 is compatible with Swift 5.10, you can still use it in your projects. + +### Changed + +- Changed CI service to GitHub Actions +- Changed minumum iOS version to 12.0 - [#24](https://github.com/FabrizioBrancati/Queuer/issues/24) +- Changed minimum macOS version to 10.13 +- Changed minimum tvOS version to 12.0 +- Changed minimum watchOS version to 4.0 +- Changed minimum macCatalyst version to 13.0 + +### Added + +- Added visionOS 1.0 support +- Added full Linux support +- Added manual finish feature to `ConcurrentOperation` class, more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#manually-finish-an-operation) - [#28](https://github.com/FabrizioBrancati/Queuer/issues/28) +- Added new `GroupOperation` operation type, more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#group-operations) - [#14](https://github.com/FabrizioBrancati/Queuer/issues/14) [#17](https://github.com/FabrizioBrancati/Queuer/pull/17) +- Added support to Xcode 15.3 and Swift 5.10 +- Added `macCatalyst` support +- Added Swift Package Index documentation support - [#26](https://github.com/FabrizioBrancati/Queuer/issues/26) [#30](https://github.com/FabrizioBrancati/Queuer/issues/30) +- Added Dependabot support + +### Fixed + +- Fixed a `Scheduler` bug that may prevent to correctly call the event handler + +### Improved + +- Improved tests - [#20](https://github.com/FabrizioBrancati/Queuer/pull/20) +- Improved [CONTRIBUTING.md](https://github.com/FabrizioBrancati/Queuer/blob/main/.github/CONTRIBUTING.md) guidelines + +### Removed + +- Removed `SynchronousOperation`. Use a queue with `maxConcurrentOperationCount` set to `1` to execute a synchronous queue +- Removed `isAsynchronous` variable from `ConcurrentOperation` as always ignored by `OperationQueue`s. You can override it anyway if you need to, since it's inferred from the `Operation` class +- Removed `hasFailed` variable from `ConcurrentOperation` class as it was deprecated in version 2.0.1 +- Removed `finish(_ hasFailed: Bool)` function from `ConcurrentOperation` class as it was deprecated in version 2.0.1 +- Removed State Restoration feature as it was not fully working and never went out of beta +- Removed SwiftLint support +- Removed CocoaPods support +- Removed Carthage support +- Removed Coveralls support +- Removed Slather support +- Removed Jazzy support + +Thanks to [Kalzem](https://github.com/Kalzem), [changmingw96](https://github.com/changmingw96), [cristianilea-lateral](https://github.com/cristianilea-lateral), [kradalby](https://github.com/kradalby), [mradzinski](https://github.com/mradzinski) and [marinofaggiana](https://github.com/marinofaggiana) for this release. ## [2.1.1](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.1.1) - Swift 5.1 Support + ### 6 Nov 2019 + ### Added + - Added support to Xcode 11.2 and Swift 5.1 ### Improved -- Updated SwiftLint to 0.35.0 ---- +- Updated SwiftLint to 0.35.0 ## [2.1.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.1.0) - Swift 5.0 Support + ### 12 Apr 2019 + ### Added -- Added support to Xcode 10.2 and Swift 5.0 ---- +- Added support to Xcode 10.2 and Swift 5.0 ## [2.0.1](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.0.1) - Better APIs + ### 26 Dec 2018 + ### Changed + - Renamed `open func finish(_ hasFailed: Bool)` to `open func finish(success: Bool = true)`, the old one has been deprecated but still valid [#12](https://github.com/FabrizioBrancati/Queuer/issues/12) - Renamed `hasFailed` variable to `success`, the old one has been deprecated but still valid [#12](https://github.com/FabrizioBrancati/Queuer/issues/12) ### Improved + - Updated SwiftLint to 0.29.2 Thanks to [@zykloman](https://github.com/zykloman) for this release ---- - ## [2.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/2.0.0) - Let Me Retry + ### 1 Nov 2018 + ### Added + - Added support to Xcode 10 and Swift 4.2 - Added retry feature to `ConcurrentOperation` class [#10](https://github.com/FabrizioBrancati/Queuer/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 @@ -60,106 +125,125 @@ Thanks to [@zykloman](https://github.com/zykloman) for this release - Added queue state restoration (beta) feature, more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#queue-state-restoration-beta) ### 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 } ``` + 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 watchOS 2.0 support in favor of watchOS 3.0, thanks to an App Store submission bug [#11](https://github.com/FabrizioBrancati/Queuer/issues/11) - Removed Hound CI -Thanks to [@SureshSc](https://github.com/SureshSc), [@zykloman](https://github.com/zykloman) and [@debjitk](https://github.com/debjitk) for this release - ---- +Thanks to [SureshSc](https://github.com/SureshSc), [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 + ### 7 Jul 2018 + ### Added + - Added `QualityOfService` on Linux - Deprecated `RequestOperation`, it will be removed in Queuer 2 ### Improved + - Updated SwiftLint to 0.26.0 - Improved code with new SwiftLint rules ---- - ## [1.3.1](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.3.1) - Swift 4.1 Support + ### 2 Apr 2018 + ### Added + - Added support to Xcode 9.3 and Swift 4.1 ### Improved -- `OperationQueue` in Queuer class is now `open` -Thanks to [@BabyAzerty](https://github.com/BabyAzerty) for this release +- `OperationQueue` in Queuer class is now `open` ---- +Thanks to [BabyAzerty](https://github.com/BabyAzerty) for this release ## [1.3.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.3.0) - Open Everything + ### 18 Feb 2018 + ### Added + - Added `swift_version` property in podspec file for CocoaPods 1.4.0 - Added Hound CI ### Improved + - `body`, `headers` and `query` parameters in RequestOperation class may now be `nil` - RequestOperation class and all of its functions are now `open` - `session` object in RequestOperation class in now open and has `waitsForConnectivity` sets to `true` for iOS 11 or later by default - Updated SwiftLint to 0.25.0 ### Fixed + - Now Swift Package Manager correctly builds Queuer with Swift 4 - Removed `self` captures ---- - ## [1.2.1](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.2.1) - Unwanted Alert + ### 22 Oct 2017 + ### Fixed -- Removed alert on Xcode 9 that shows the ability to convert the code to Swift 4 even it's already written in Swift 4 ---- +- Removed alert on Xcode 9 that shows the ability to convert the code to Swift 4 even it's already written in Swift 4 ## [1.2.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.2.0) - Swift 4 Support + ### 23 Sep 2017 + ### Added + - Added support to Swift 4 and Xcode 9 ### Improved + - Using new Xcode 9 build system - Updated SwiftLint to 0.22.0 ---- - ## [1.1.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.1.0) - Quality Of Service + ### 1 Sep 2017 + ### Added + - Added `qualityOfService` property on Queuer class - Added `ddChainedOperations(_ operations: Operation..., completionHandler:` convenience function on Queuer class ### Improved + - Improved the `init` function on Queuer class with `maxConcurrentOperationCount` and `qualityOfService` properties, both with a default value, so no changes are required - Updated SwiftLint to 0.21.0 ### Fixed + - Now `ConcurrentOperation` is subclassable with `open` instead of `public` Access Control [#2](https://github.com/FabrizioBrancati/Queuer/issues/2) - Fixed tests that sometimes fails ---- - ## [1.0.0](https://github.com/FabrizioBrancati/Queuer/releases/tag/1.0.0) - First Queue + ### 26 Jul 2017 + ### Added + - Added `ConcurrentOperation` to create asynchronous operations - Added `Queuer` to handle a `shared` queue or create a custom one - Added `RequestOperation` to create network request operations diff --git a/LICENSE b/LICENSE index edcfc06..ded3a55 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 - 2018 Fabrizio Brancati +Copyright (c) 2017 - 2024 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/Package.resolved b/Package.resolved new file mode 100644 index 0000000..e65252d --- /dev/null +++ b/Package.resolved @@ -0,0 +1,23 @@ +{ + "pins" : [ + { + "identity" : "swift-docc-plugin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-docc-plugin", + "state" : { + "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-docc-symbolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-docc-symbolkit", + "state" : { + "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", + "version" : "1.0.0" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift index fe676f5..91a0d91 100644 --- a/Package.swift +++ b/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.9 // // Package.swift // Queuer // // MIT License // -// Copyright (c) 2017 - 2018 Fabrizio Brancati. +// Copyright (c) 2017 - 2024 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 @@ -30,17 +30,21 @@ import PackageDescription let package = Package( name: "Queuer", platforms: [ - .iOS(.v8), - .macOS(.v10_10), - .tvOS(.v9), - .watchOS(.v3) + .iOS(.v12), + .macOS(.v10_13), + .macCatalyst(.v13), + .tvOS(.v12), + .watchOS(.v4), + .visionOS(.v1) ], products: [ .library(name: "Queuer", targets: ["Queuer"]) ], + dependencies: [ + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0") + ], targets: [ .target(name: "Queuer"), .testTarget(name: "QueuerTests", dependencies: ["Queuer"]) - ], - swiftLanguageVersions: [.v5] + ] ) diff --git a/Queuer.podspec b/Queuer.podspec deleted file mode 100644 index 61af74a..0000000 --- a/Queuer.podspec +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'Queuer' - s.module_name = 'Queuer' - s.version = '2.1.1' - 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' - s.authors = { 'Fabrizio Brancati' => 'fabrizio.brancati@gmail.com' } - s.social_media_url = 'https://twitter.com/infinity4all' - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.source = { :git => 'https://github.com/FabrizioBrancati/Queuer.git', :tag => s.version } - s.documentation_url = 'https://github.fabriziobrancati.com/documentation/Queuer/' - - s.swift_version = '5.1' - - s.source_files = 'Sources/**/*.swift' - - s.ios.deployment_target = '8.0' - s.osx.deployment_target = '10.10' - s.tvos.deployment_target = '9.0' - s.watchos.deployment_target = '3.0' -end diff --git a/Queuer.xcodeproj/project.pbxproj b/Queuer.xcodeproj/project.pbxproj deleted file mode 100644 index 0648e8f..0000000 --- a/Queuer.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1143 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* 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, ); }; }; - 49B28E2D1F27EDCC00D0819A /* Queuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C7BCC11F26938F00F4FFBC /* Queuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 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 */; }; - 49C7BCD11F26938F00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; - 49C7BCD21F26938F00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.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 */; }; - 49C7BCD81F26939900F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; - 49C7BCD91F26939900F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCDB1F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; }; - 49C7BCDC1F26939A00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; }; - 49C7BCDE1F26939A00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; - 49C7BCDF1F26939A00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCE11F26939A00F4FFBC /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */; }; - 49C7BCE21F26939A00F4FFBC /* Queuer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */; }; - 49C7BCE41F26939A00F4FFBC /* Semaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */; }; - 49C7BCE51F26939A00F4FFBC /* SynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */; }; - 49C7BCE71F26939F00F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; }; - 49C7BCE81F26939F00F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; }; - 49C7BCEA1F26939F00F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; }; - 49C7BCEB1F26939F00F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; }; - 49C7BCED1F2693A000F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; }; - 49C7BCEE1F2693A000F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; }; - 49C7BCF01F2693A000F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; }; - 49C7BCF11F2693A000F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; }; - 49C7BCF31F2693A100F4FFBC /* ConcurrentOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */; }; - 49C7BCF41F2693A100F4FFBC /* QueuerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */; }; - 49C7BCF61F2693A100F4FFBC /* SemaphoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */; }; - 49C7BCF71F2693A100F4FFBC /* SynchronousOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */; }; - 49E803C6217FE8E80001B47A /* OperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803C5217FE8E80001B47A /* OperationState.swift */; }; - 49E803C7217FE8E80001B47A /* OperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803C5217FE8E80001B47A /* OperationState.swift */; }; - 49E803C8217FE8E80001B47A /* OperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803C5217FE8E80001B47A /* OperationState.swift */; }; - 49E803C9217FE8E80001B47A /* OperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803C5217FE8E80001B47A /* OperationState.swift */; }; - 49E803CB21868A310001B47A /* OperationStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803CA21868A310001B47A /* OperationStateTests.swift */; }; - 49E803CC21868A310001B47A /* OperationStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803CA21868A310001B47A /* OperationStateTests.swift */; }; - 49E803CD21868A310001B47A /* OperationStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E803CA21868A310001B47A /* OperationStateTests.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 493F572A1F21F32B009EC8FA /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4995D7301F21E19B00A34E6E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 493F571F1F21F32B009EC8FA; - remoteInfo = Queuer; - }; - 4995D7441F21E19C00A34E6E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4995D7301F21E19B00A34E6E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 4995D7381F21E19B00A34E6E; - remoteInfo = Queuer; - }; - 4995D7701F21ED1C00A34E6E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4995D7301F21E19B00A34E6E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 4995D7651F21ED1B00A34E6E; - remoteInfo = Queuer; - }; -/* End PBXContainerItemProxy section */ - -/* 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; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scheduler.swift; sourceTree = ""; }; - 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; 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; }; - 4995D7661F21ED1B00A34E6E /* Queuer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Queuer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4995D76E1F21ED1C00A34E6E /* QueuerTests tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QueuerTests tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 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 = ""; }; - 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 = ""; }; - 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 = ""; }; - 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousOperation.swift; sourceTree = ""; }; - 49C7BCC11F26938F00F4FFBC /* Queuer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Queuer.h; sourceTree = ""; }; - 49E803C5217FE8E80001B47A /* OperationState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationState.swift; sourceTree = ""; }; - 49E803CA21868A310001B47A /* OperationStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationStateTests.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 493F571C1F21F32B009EC8FA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 493F57251F21F32B009EC8FA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 493F57291F21F32B009EC8FA /* Queuer.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7351F21E19B00A34E6E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D73F1F21E19C00A34E6E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4995D7431F21E19C00A34E6E /* Queuer.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7541F21EA3F00A34E6E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7621F21ED1B00A34E6E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D76B1F21ED1C00A34E6E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4995D76F1F21ED1C00A34E6E /* Queuer.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 4995D72F1F21E19B00A34E6E = { - isa = PBXGroup; - children = ( - 49C7BCB51F26938F00F4FFBC /* Sources */, - 49C7BCAB1F26938F00F4FFBC /* Tests */, - 4995D73A1F21E19B00A34E6E /* Products */, - ); - sourceTree = ""; - }; - 4995D73A1F21E19B00A34E6E /* Products */ = { - isa = PBXGroup; - children = ( - 4995D7391F21E19B00A34E6E /* Queuer.framework */, - 4995D7421F21E19C00A34E6E /* QueuerTests iOS.xctest */, - 4995D7581F21EA3F00A34E6E /* Queuer.framework */, - 4995D7661F21ED1B00A34E6E /* Queuer.framework */, - 4995D76E1F21ED1C00A34E6E /* QueuerTests tvOS.xctest */, - 493F57201F21F32B009EC8FA /* Queuer.framework */, - 493F57281F21F32B009EC8FA /* QueuerTests macOS.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 49C7BCAB1F26938F00F4FFBC /* Tests */ = { - isa = PBXGroup; - children = ( - 49C7BCAC1F26938F00F4FFBC /* Info.plist */, - 49C7BCAE1F26938F00F4FFBC /* QueuerTests */, - ); - path = Tests; - sourceTree = ""; - }; - 49C7BCAE1F26938F00F4FFBC /* QueuerTests */ = { - isa = PBXGroup; - children = ( - 49C7BCAF1F26938F00F4FFBC /* ConcurrentOperationTests.swift */, - 49E803CA21868A310001B47A /* OperationStateTests.swift */, - 49C7BCB01F26938F00F4FFBC /* QueuerTests.swift */, - 4946BDFA214D5C0100FAFC84 /* SchedulerTests.swift */, - 49C7BCB21F26938F00F4FFBC /* SemaphoreTests.swift */, - 49C7BCB31F26938F00F4FFBC /* SynchronousOperationTests.swift */, - ); - path = QueuerTests; - sourceTree = ""; - }; - 49C7BCB51F26938F00F4FFBC /* Sources */ = { - isa = PBXGroup; - children = ( - 49C7BCB71F26938F00F4FFBC /* Info.plist */, - 49C7BCC11F26938F00F4FFBC /* Queuer.h */, - 49C7BCBA1F26938F00F4FFBC /* Queuer */, - ); - path = Sources; - sourceTree = ""; - }; - 49C7BCBA1F26938F00F4FFBC /* Queuer */ = { - isa = PBXGroup; - children = ( - 49C7BCBB1F26938F00F4FFBC /* ConcurrentOperation.swift */, - 49E803C5217FE8E80001B47A /* OperationState.swift */, - 49C7BCBC1F26938F00F4FFBC /* Queuer.swift */, - 4946BDF5214D586900FAFC84 /* Scheduler.swift */, - 49C7BCBE1F26938F00F4FFBC /* Semaphore.swift */, - 49C7BCBF1F26938F00F4FFBC /* SynchronousOperation.swift */, - ); - path = Queuer; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 493F571D1F21F32B009EC8FA /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 49B28E2C1F27EDCB00D0819A /* Queuer.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7361F21E19B00A34E6E /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 49C7BCD41F26938F00F4FFBC /* Queuer.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7551F21EA3F00A34E6E /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 49B28E2E1F27EDCC00D0819A /* Queuer.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7631F21ED1B00A34E6E /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 49B28E2D1F27EDCC00D0819A /* Queuer.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 493F571F1F21F32B009EC8FA /* Queuer macOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 493F57311F21F32B009EC8FA /* Build configuration list for PBXNativeTarget "Queuer macOS" */; - buildPhases = ( - 493F571B1F21F32B009EC8FA /* Sources */, - 493F571C1F21F32B009EC8FA /* Frameworks */, - 493F571D1F21F32B009EC8FA /* Headers */, - 493F571E1F21F32B009EC8FA /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Queuer macOS"; - productName = Queuer; - productReference = 493F57201F21F32B009EC8FA /* Queuer.framework */; - productType = "com.apple.product-type.framework"; - }; - 493F57271F21F32B009EC8FA /* QueuerTests macOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 493F57341F21F32B009EC8FA /* Build configuration list for PBXNativeTarget "QueuerTests macOS" */; - buildPhases = ( - 493F57241F21F32B009EC8FA /* Sources */, - 493F57251F21F32B009EC8FA /* Frameworks */, - 493F57261F21F32B009EC8FA /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 493F572B1F21F32B009EC8FA /* PBXTargetDependency */, - ); - name = "QueuerTests macOS"; - productName = QueuerTests; - productReference = 493F57281F21F32B009EC8FA /* QueuerTests macOS.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 4995D7381F21E19B00A34E6E /* Queuer iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4995D74D1F21E19C00A34E6E /* Build configuration list for PBXNativeTarget "Queuer iOS" */; - buildPhases = ( - 4995D7341F21E19B00A34E6E /* Sources */, - 4995D7351F21E19B00A34E6E /* Frameworks */, - 4995D7361F21E19B00A34E6E /* Headers */, - 4995D7371F21E19B00A34E6E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Queuer iOS"; - productName = Queuer; - productReference = 4995D7391F21E19B00A34E6E /* Queuer.framework */; - productType = "com.apple.product-type.framework"; - }; - 4995D7411F21E19C00A34E6E /* QueuerTests iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4995D7501F21E19C00A34E6E /* Build configuration list for PBXNativeTarget "QueuerTests iOS" */; - buildPhases = ( - 4995D73E1F21E19C00A34E6E /* Sources */, - 4995D73F1F21E19C00A34E6E /* Frameworks */, - 4995D7401F21E19C00A34E6E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 4995D7451F21E19C00A34E6E /* PBXTargetDependency */, - ); - name = "QueuerTests iOS"; - productName = QueuerTests; - productReference = 4995D7421F21E19C00A34E6E /* QueuerTests iOS.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 4995D7571F21EA3F00A34E6E /* Queuer watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4995D75D1F21EA3F00A34E6E /* Build configuration list for PBXNativeTarget "Queuer watchOS" */; - buildPhases = ( - 4995D7531F21EA3F00A34E6E /* Sources */, - 4995D7541F21EA3F00A34E6E /* Frameworks */, - 4995D7551F21EA3F00A34E6E /* Headers */, - 4995D7561F21EA3F00A34E6E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Queuer watchOS"; - productName = Queuer; - productReference = 4995D7581F21EA3F00A34E6E /* Queuer.framework */; - productType = "com.apple.product-type.framework"; - }; - 4995D7651F21ED1B00A34E6E /* Queuer tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4995D7771F21ED1C00A34E6E /* Build configuration list for PBXNativeTarget "Queuer tvOS" */; - buildPhases = ( - 4995D7611F21ED1B00A34E6E /* Sources */, - 4995D7621F21ED1B00A34E6E /* Frameworks */, - 4995D7631F21ED1B00A34E6E /* Headers */, - 4995D7641F21ED1B00A34E6E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Queuer tvOS"; - productName = Queuer; - productReference = 4995D7661F21ED1B00A34E6E /* Queuer.framework */; - productType = "com.apple.product-type.framework"; - }; - 4995D76D1F21ED1C00A34E6E /* QueuerTests tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4995D77A1F21ED1C00A34E6E /* Build configuration list for PBXNativeTarget "QueuerTests tvOS" */; - buildPhases = ( - 4995D76A1F21ED1C00A34E6E /* Sources */, - 4995D76B1F21ED1C00A34E6E /* Frameworks */, - 4995D76C1F21ED1C00A34E6E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 4995D7711F21ED1C00A34E6E /* PBXTargetDependency */, - ); - name = "QueuerTests tvOS"; - productName = QueuerTests; - productReference = 4995D76E1F21ED1C00A34E6E /* QueuerTests tvOS.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 4995D7301F21E19B00A34E6E /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0830; - LastUpgradeCheck = 0900; - ORGANIZATIONNAME = "Fabrizio Brancati"; - TargetAttributes = { - 493F571F1F21F32B009EC8FA = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; - }; - 493F57271F21F32B009EC8FA = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Automatic; - }; - 4995D7381F21E19B00A34E6E = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; - }; - 4995D7411F21E19C00A34E6E = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; - }; - 4995D7571F21EA3F00A34E6E = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; - }; - 4995D7651F21ED1B00A34E6E = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; - }; - 4995D76D1F21ED1C00A34E6E = { - CreatedOnToolsVersion = 8.3.3; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 4995D7331F21E19B00A34E6E /* Build configuration list for PBXProject "Queuer" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 4995D72F1F21E19B00A34E6E; - productRefGroup = 4995D73A1F21E19B00A34E6E /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 4995D7381F21E19B00A34E6E /* Queuer iOS */, - 493F571F1F21F32B009EC8FA /* Queuer macOS */, - 4995D7651F21ED1B00A34E6E /* Queuer tvOS */, - 4995D7571F21EA3F00A34E6E /* Queuer watchOS */, - 4995D7411F21E19C00A34E6E /* QueuerTests iOS */, - 493F57271F21F32B009EC8FA /* QueuerTests macOS */, - 4995D76D1F21ED1C00A34E6E /* QueuerTests tvOS */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 493F571E1F21F32B009EC8FA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 493F57261F21F32B009EC8FA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7371F21E19B00A34E6E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7401F21E19C00A34E6E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7561F21EA3F00A34E6E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7641F21ED1B00A34E6E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D76C1F21ED1C00A34E6E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 493F571B1F21F32B009EC8FA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 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 */, - 49E803C7217FE8E80001B47A /* OperationState.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 493F57241F21F32B009EC8FA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 49C7BCEE1F2693A000F4FFBC /* QueuerTests.swift in Sources */, - 49E803CC21868A310001B47A /* OperationStateTests.swift in Sources */, - 49C7BCF01F2693A000F4FFBC /* SemaphoreTests.swift in Sources */, - 4946BDFC214D5C0100FAFC84 /* SchedulerTests.swift in Sources */, - 49C7BCED1F2693A000F4FFBC /* ConcurrentOperationTests.swift in Sources */, - 49C7BCF11F2693A000F4FFBC /* SynchronousOperationTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7341F21E19B00A34E6E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 49C7BCCE1F26938F00F4FFBC /* ConcurrentOperation.swift in Sources */, - 49C7BCD21F26938F00F4FFBC /* SynchronousOperation.swift in Sources */, - 49C7BCCF1F26938F00F4FFBC /* Queuer.swift in Sources */, - 4946BDF6214D586900FAFC84 /* Scheduler.swift in Sources */, - 49C7BCD11F26938F00F4FFBC /* Semaphore.swift in Sources */, - 49E803C6217FE8E80001B47A /* OperationState.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D73E1F21E19C00A34E6E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 49C7BCE81F26939F00F4FFBC /* QueuerTests.swift in Sources */, - 49E803CB21868A310001B47A /* OperationStateTests.swift in Sources */, - 49C7BCEA1F26939F00F4FFBC /* SemaphoreTests.swift in Sources */, - 4946BDFB214D5C0100FAFC84 /* SchedulerTests.swift in Sources */, - 49C7BCE71F26939F00F4FFBC /* ConcurrentOperationTests.swift in Sources */, - 49C7BCEB1F26939F00F4FFBC /* SynchronousOperationTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7531F21EA3F00A34E6E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 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 */, - 49E803C9217FE8E80001B47A /* OperationState.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D7611F21ED1B00A34E6E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 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 */, - 49E803C8217FE8E80001B47A /* OperationState.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 4995D76A1F21ED1C00A34E6E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 49C7BCF41F2693A100F4FFBC /* QueuerTests.swift in Sources */, - 49E803CD21868A310001B47A /* OperationStateTests.swift in Sources */, - 49C7BCF61F2693A100F4FFBC /* SemaphoreTests.swift in Sources */, - 4946BDFD214D5C0100FAFC84 /* SchedulerTests.swift in Sources */, - 49C7BCF31F2693A100F4FFBC /* ConcurrentOperationTests.swift in Sources */, - 49C7BCF71F2693A100F4FFBC /* SynchronousOperationTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 493F572B1F21F32B009EC8FA /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 493F571F1F21F32B009EC8FA /* Queuer macOS */; - targetProxy = 493F572A1F21F32B009EC8FA /* PBXContainerItemProxy */; - }; - 4995D7451F21E19C00A34E6E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 4995D7381F21E19B00A34E6E /* Queuer iOS */; - targetProxy = 4995D7441F21E19C00A34E6E /* PBXContainerItemProxy */; - }; - 4995D7711F21ED1C00A34E6E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 4995D7651F21ED1B00A34E6E /* Queuer tvOS */; - targetProxy = 4995D7701F21ED1C00A34E6E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 493F57321F21F32B009EC8FA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - 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; - PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-macOS"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 493F57331F21F32B009EC8FA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - 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; - PRODUCT_BUNDLE_IDENTIFIER = "com.FabrizioBrancati.Queuer-macOS"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - }; - name = Release; - }; - 493F57351F21F32B009EC8FA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_IDENTITY = "-"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; - PRODUCT_BUNDLE_IDENTIFIER = com.FabrizioBrancati.QueuerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - SWIFT_VERSION = 5.1; - }; - name = Debug; - }; - 493F57361F21F32B009EC8FA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_IDENTITY = "-"; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; - PRODUCT_BUNDLE_IDENTIFIER = com.FabrizioBrancati.QueuerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - SWIFT_VERSION = 5.1; - }; - name = Release; - }; - 4995D74B1F21E19C00A34E6E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; - CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; - CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - 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; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2.1.1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_SHADOW = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNKNOWN_PRAGMAS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_PARAMETER = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; - 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_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 5.1; - TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 3.0; - }; - name = Debug; - }; - 4995D74C1F21E19C00A34E6E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; - CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; - CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_ASSIGN_ENUM = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - 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; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2.1.1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; - GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_SHADOW = YES; - GCC_WARN_SIGN_COMPARE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNKNOWN_PRAGMAS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_LABEL = YES; - GCC_WARN_UNUSED_PARAMETER = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; - 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_COMPILATION_MODE = wholemodule; - SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 5.1; - TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 9.0; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 3.0; - }; - name = Release; - }; - 4995D74E1F21E19C00A34E6E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - 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"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 4995D74F1F21E19C00A34E6E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_ENABLE_MODULES = YES; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - 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"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - }; - name = Release; - }; - 4995D7511F21E19C00A34E6E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.FabrizioBrancati.QueuerTests; - PRODUCT_MODULE_NAME = "$(PRODUCT_NAME:c99extidentifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = iphoneos; - SWIFT_VERSION = 5.1; - }; - name = Debug; - }; - 4995D7521F21E19C00A34E6E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.FabrizioBrancati.QueuerTests; - PRODUCT_MODULE_NAME = "$(PRODUCT_NAME:c99extidentifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = iphoneos; - SWIFT_VERSION = 5.1; - }; - name = Release; - }; - 4995D75E1F21EA3F00A34E6E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - 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"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Debug; - }; - 4995D75F1F21EA3F00A34E6E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - 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"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Release; - }; - 4995D7781F21ED1C00A34E6E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - 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"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Debug; - }; - 4995D7791F21ED1C00A34E6E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - 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"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Release; - }; - 4995D77B1F21ED1C00A34E6E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_IDENTITY = ""; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.FabrizioBrancati.QueuerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 10.2; - }; - name = Debug; - }; - 4995D77C1F21ED1C00A34E6E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_IDENTITY = ""; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.FabrizioBrancati.QueuerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 10.2; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 493F57311F21F32B009EC8FA /* Build configuration list for PBXNativeTarget "Queuer macOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 493F57321F21F32B009EC8FA /* Debug */, - 493F57331F21F32B009EC8FA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 493F57341F21F32B009EC8FA /* Build configuration list for PBXNativeTarget "QueuerTests macOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 493F57351F21F32B009EC8FA /* Debug */, - 493F57361F21F32B009EC8FA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4995D7331F21E19B00A34E6E /* Build configuration list for PBXProject "Queuer" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4995D74B1F21E19C00A34E6E /* Debug */, - 4995D74C1F21E19C00A34E6E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4995D74D1F21E19C00A34E6E /* Build configuration list for PBXNativeTarget "Queuer iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4995D74E1F21E19C00A34E6E /* Debug */, - 4995D74F1F21E19C00A34E6E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4995D7501F21E19C00A34E6E /* Build configuration list for PBXNativeTarget "QueuerTests iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4995D7511F21E19C00A34E6E /* Debug */, - 4995D7521F21E19C00A34E6E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4995D75D1F21EA3F00A34E6E /* Build configuration list for PBXNativeTarget "Queuer watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4995D75E1F21EA3F00A34E6E /* Debug */, - 4995D75F1F21EA3F00A34E6E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4995D7771F21ED1C00A34E6E /* Build configuration list for PBXNativeTarget "Queuer tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4995D7781F21ED1C00A34E6E /* Debug */, - 4995D7791F21ED1C00A34E6E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 4995D77A1F21ED1C00A34E6E /* Build configuration list for PBXNativeTarget "QueuerTests tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4995D77B1F21ED1C00A34E6E /* Debug */, - 4995D77C1F21ED1C00A34E6E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 4995D7301F21E19B00A34E6E /* Project object */; -} diff --git a/Queuer.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Queuer.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index e551f72..0000000 --- a/Queuer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Queuer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queuer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/Queuer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Queuer.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Queuer.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 0c67376..0000000 --- a/Queuer.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme deleted file mode 100644 index be2f8d0..0000000 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer iOS.xcscheme +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme deleted file mode 100644 index 394e377..0000000 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer macOS.xcscheme +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme deleted file mode 100644 index a0fc727..0000000 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer tvOS.xcscheme +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme b/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme deleted file mode 100644 index 485d9c2..0000000 --- a/Queuer.xcodeproj/xcshareddata/xcschemes/Queuer watchOS.xcscheme +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/README.md b/README.md index fa659b5..090eef7 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,15 @@ -

-Queuer Banner -

- -[![Build Status](https://travis-ci.com/FabrizioBrancati/Queuer.svg?branch=master)](https://travis-ci.com/FabrizioBrancati/Queuer) -[![Coverage Status](https://coveralls.io/repos/github/FabrizioBrancati/Queuer/badge.svg?branch=master)](https://coveralls.io/github/FabrizioBrancati/Queuer?branch=master) -[![Maintainability](https://api.codeclimate.com/v1/badges/ce03faaf6abe697458ed/maintainability)](https://codeclimate.com/github/FabrizioBrancati/Queuer/maintainability) -[![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) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/dc5a0e93970b42308ddd333c3bcc22ce)](https://www.codacy.com/manual/FabrizioBrancati/Queuer) -
-[![Documentation](https://github.fabriziobrancati.com/documentation/Queuer/badge.svg)](https://github.fabriziobrancati.com/documentation/Queuer/) -[![Swift Package Manager Compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) -[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) -
-[![Version](https://img.shields.io/cocoapods/v/Queuer.svg?style=flat)][Documentation] -[![Language](https://img.shields.io/badge/language-Swift%205.0%20%7C%205.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-cc9c00.svg)][Documentation] -[![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://github.com/FabrizioBrancati/Queuer/blob/master/LICENSE) - ---- - -

- Features • - Requirements • - Installing • - Usage • - Documentation • - Changelog • - Communication • - Contributing • - Author • - License -

- ---- - -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 asynchronous and synchronous task easily, all managed by a queue, with just a few lines. +# Queuer + +[![GitHub Release](https://img.shields.io/github/v/release/FabrizioBrancati/Queuer?label=Release)](https://swiftpackageindex.com/FabrizioBrancati/Queuer) +[![Swift Versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FFabrizioBrancati%2FQueuer%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/FabrizioBrancati/Queuer) +[![Swift Platforms](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FFabrizioBrancati%2FQueuer%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/FabrizioBrancati/Queuer) + +## 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 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) - [x] Easy to use - [x] Well documented (100% documented) @@ -54,154 +23,92 @@ Here is the list of all the features: - [x] Create semaphores - [x] Create and handle schedules - [x] Automatically or manually retry an operation -- [x] Ability to restore uncompleted operations -- [ ] Improve the state restoration feature - [ ] Throttling between each automatic operation retry -- [ ] Data layer that every operation inside an `OperationQueue` can access - -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...10.1 | 2.0.0...2.0.1 | 8.0+ | 10.10+ | 9.0+ | 3.0+ | ![✓] | -| 5.0...5.1 | 10.2...11.2 | 2.1.0...2.1.1 | 8.0+ | 10.10+ | 9.0+ | 3.0+ | ![✓] | - -Installing -========== - -See [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) section to check Swift, Xcode, Queuer and OS versions. - -### Manual -- Open and build the framework from the project (**Queuer.xcodeproj**) -- Import Queuer.framework into your project -- Import the framework with ```import Queuer``` -- Enjoy! - -### CocoaPods -- Create a **Podfile** in your **project directory** and write into: - - ```ruby - platform :ios, '8.0' - xcodeproj 'Project.xcodeproj' - use_frameworks! - - pod 'Queuer' - ``` -- Change **"Project"** with your **real project name** -- Open **Terminal**, go to your **project directory** and type: ```pod install``` -- Import the framework with ```import Queuer``` -- Enjoy! - -### Carthage -- Create a **Cartfile** in your **project directory** and write into: - ```ruby - github "FabrizioBrancati/Queuer" - ``` -- Open **Terminal**, go to **project directory** and type: ```carthage update``` -- **Include the created Framework** in your project -- **Add Build Phase** with the following contents: - - ```sh - /usr/local/bin/carthage copy-frameworks - ``` +## Requirements - Add the paths to the Queuer framework under **Input Files** +| **Swift** | **Queuer** | **iOS** | **macOS** | **macCatalyst** | **tvOS** | **watchOS** | **visionOS** | **Linux** | +|------------|---------------|---------|------------|-----------------|-----------|-------------|--------------|-----------| +| 3.1...3.2 | 1.0.0...1.1.0 | 8.0+ | 10.10+ | | 9.0+ | 2.0+ | | ✅ | +| 4.0 | 1.3.0 | 8.0+ | 10.10+ | | 9.0+ | 2.0+ | | ✅ | +| 4.1 | 1.3.1...1.3.2 | 8.0+ | 10.10+ | | 9.0+ | 2.0+ | | ✅ | +| 4.2 | 2.0.0...2.0.1 | 8.0+ | 10.10+ | | 9.0+ | 3.0+ | | ✅ | +| 5.0...5.10 | 2.1.0...2.2.0 | 8.0+ | 10.10+ | | 9.0+ | 3.0+ | | ✅ | +| 5.9...5.10 | 3.0.0 | 12.0+ | 10.13+ | 13.0+ | 12.0+ | 4.0+ | 1.0+ | ✅ | - ```sh - $(SRCROOT)/Carthage/Build/iOS/Queuer.framework - ``` - - Add the paths to the copied frameworks to the **Output Files** - - ```sh - $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Queuer.framework - ``` +## Installing - This script works around an [App Store submission bug](http://www.openradar.me/radar?id=6409498411401216) triggered by universal binaries and ensures that necessary bitcode-related files are copied when archiving -- **(Optional)** Add Build Phase with the following contents +See [Requirements](https://github.com/FabrizioBrancati/Queuer#requirements) section to check Swift, Queuer, and OS versions. - ```sh - /usr/local/bin/carthage outdated --xcode-warnings - ``` +In your `Package.swift` Swift Package Manager manifest, add the following dependency to your `dependencies` argument: - To automatically warn you when one of your dependencies is out of date -- Import the framework with ```import Queuer``` -- Enjoy! +```swift +.package(url: "https://github.com/FabrizioBrancati/Queuer.git", from: "3.0.0"), +``` -### Swift Package Manager -- Create a **Package.swift** file in your **project directory** and write into: +Add the dependency to any targets you've declared in your manifest: - ```swift - // swift-tools-version:5.1 - import PackageDescription - - let package = Package( - name: "Project", - products: [ - .executable(name: "Project", targets: ["Project"]) - ], - dependencies: [ - .package(url: "https://github.com/FabrizioBrancati/Queuer.git", .upToNextMajor(from: "2.0.0")) - ], - targets: [ - .target(name: "Project", dependencies: ["Queuer"]) - ] - ) - ``` -- Change **"Project"** with your **real project name** -- Open **Terminal**, go to **project directory** and type: ```swift build``` -- Import the framework with ```import Queuer``` -- Enjoy! +```swift +.target( + name: "MyTarget", + dependencies: [ + .product(name: "Queuer", package: "Queuer"), + ] +), +``` -Usage -===== +## 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) +- [Group Oprations](https://github.com/FabrizioBrancati/Queuer#group-operations) - [Queue States](https://github.com/FabrizioBrancati/Queuer#queue-states) +- [Synchronous Queue](https://github.com/FabrizioBrancati/Queuer#synchronous-queue) - [Asynchronous Operation](https://github.com/FabrizioBrancati/Queuer#asynchronous-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) +- [Manually Finish an Operation](https://github.com/FabrizioBrancati/Queuer#manually-finish-an-operation) - [Scheduler](https://github.com/FabrizioBrancati/Queuer#scheduler) - [Semaphore](https://github.com/FabrizioBrancati/Queuer#semaphore) -- [Queue State Restoration (Beta)](https://github.com/FabrizioBrancati/Queuer#queue-state-restoration-beta) ### Shared Queuer +Queuer offers a shared instance that you can use to add operations to a centralized queue: + ```swift Queuer.shared.addOperation(operation) ``` ### Custom Queue +You can also create a custom queue: + ```swift let queue = Queuer(name: "MyCustomQueue") ``` You can even create a queue by defining the `maxConcurrentOperationCount` and the `qualityOfService` properties: + ```swift let queue = Queuer(name: "MyCustomQueue", maxConcurrentOperationCount: Int.max, qualityOfService: .default) ``` ### Create an Operation Block -You have three methods to add an `Operation` block: -- Directly on the `queue`(or `Queuer.shared`): +You have three methods to add an `Operation` block. + +1. Directly on the `queue`(or `Queuer.shared`): + ```swift queue.addOperation { /// Your task here } ``` -- Creating a `ConcurrentOperation` with a block: +2. Creating a `ConcurrentOperation` with a block: + ```swift let concurrentOperation = ConcurrentOperation { _ in /// Your task here @@ -209,19 +116,15 @@ You have three methods to add an `Operation` block: queue.addOperation(concurrentOperation) ``` -- Creating a `SynchronousOperation` with a block: - ```swift - let synchronousOperation = SynchronousOperation { _ in - /// Your task here - } - queue.addOperation(synchronousOperation) - ``` - -> We will see how `ConcurrentOperation` and `SynchronousOperation` works later. +> [!NOTE] +> We will see how `ConcurrentOperation` works later. ### Chained Operations -Chained Operations are `Operation`s that add a dependency each other.
+ +Chained Operations are `Operation`s that add a dependency each other. + They follow the given array order, for example: `[A, B, C] = A -> B -> C -> completionBlock`. + ```swift let concurrentOperationA = ConcurrentOperation { _ in /// Your task A here @@ -235,44 +138,95 @@ queue.addChainedOperations([concurrentOperationA, concurrentOperationB]) { ``` You can also add a `completionHandler` after the queue creation with: + ```swift queue.addCompletionHandler { /// Your completion task here } ``` +### Group Operations + +Group Operations are `Operation`s that handles a group of `Operation`s with a completion handler. + +Allows the execution of a block of `Operation`s with a completion handler that will be called once all the operations are finished, for example: `[A -> [[B & C & D] -> completionHandler] -> E] -> completionHandler`. +It should usually be used with a [Chained Opetation](https://github.com/FabrizioBrancati/Queuer#chained-operations). + +```swift +let groupOperationA = GroupOperation( + [ + ConcurrentOperation { _ in + /// Your task A here + }, + ConcurrentOperation { _ in + /// Your task B here + } + ] +) + +let concurrentOperationC = ConcurrentOperation { _ in + /// Your task C here +} + +queue.addChainedOperations([groupOperationA, concurrentOperationC]) { + /// Your completion task here +} +``` + +In this case the output will be the following one: `[[A & B -> completionHandler] -> C] -> completionHandler`. + ### Queue States -- Cancel all `Operation`s in queue: + +There are a few method to handle the queue states. + +1. Cancel all `Operation`s in a queue: + ```swift queue.cancelAll() ``` -- Pause queue: + +2. Pause a queue: + ```swift 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. -- Resume queue: +> [!WARNING] +> 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. + +3. Resume a queue: + ```swift queue.resume() ``` - > To have a complete `pause` and `resume` states you must create a custom `Operation` that overrides `pause()` and `resume()` function. -- Wait until all `Operation`s are finished: +> [!WARNING] +> To have a complete `pause` and `resume` states you must create a custom `Operation` that overrides `pause()` and `resume()` function. + +4. Wait until all `Operation`s are finished: + ```swift queue.waitUntilAllOperationsAreFinished() ``` - > This function means that the queue will blocks the current thread until all `Operation`s are finished. + +> [!IMPORTANT] +> This function means that the queue will blocks the current thread until all `Operation`s are finished. + +### Synchronous Queue + +Setting the `maxConcurrentOperationCount` property of a queue to `1` will make you sure that only one task at a time will be executed. ### Asynchronous Operation + `ConcurrentOperation` is a class created to be subclassed. 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 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. For convenience it has an `init` function with a completion block: + ```swift let concurrentOperation = ConcurrentOperation { _ in /// Your task here @@ -280,27 +234,14 @@ let concurrentOperation = ConcurrentOperation { _ in concurrentOperation.addToQueue(queue) ``` -### Synchronous Operation -There are three methods to create synchronous tasks or even queue: -- Setting `maxConcurrentOperationCount` of the queue to `1`.
- By setting that property to `1` you will be sure that only one task at time will be executed. -- Using a `Semaphore` and waiting until a task has finished its job. -- Using a `SynchronousOperation`.
- It's a subclass of `ConcurrentOperation` that handles synchronous tasks.
- It's not awesome as it seems to be and is always better to create an asynchronous task, but some times it may be useful. +### Automatically Retry an Operation + +An `Operation` is passed to every closure, with it you can set and handle the retry feature. -For convenience it has an `init` function with a completion block: -```swift -let synchronousOperation = SynchronousOperation { _ in - /// Your task here -} -synchronousOperation.addToQueue(queue) -``` +By default the retry feature is disabled, to enable it simply set the `success` property to `false`. With `success` to `false` the `Operation` will retry until reaches `maximumRetries` property value. To let the `Operation` know when everything is ok, you must set `success` to `true`. -### 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 `success` property to `false`. With `success` to `false` the `Operation` will retry until reaches `maximumRetries` property value. To let the `Operation` know when everything is ok, you must set `success` to `true`.
With `currentAttempt` you can know at which attempt the `Operation` is. + ```swift let concurrentOperation = ConcurrentOperation { operation in /// Your task here @@ -313,10 +254,15 @@ let concurrentOperation = ConcurrentOperation { operation in ``` ### Manually Retry an Operation -You can 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 `success` to `true` or `false` to let the `Operation` know 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. + +You can 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 `success` to `true` or `false` to let the `Operation` know when is everything ok, like the automatic retry feature. + +To let the `Operation` retry your execution closure, you have to call the `retry()` function. 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 @@ -327,11 +273,39 @@ let concurrentOperation = ConcurrentOperation { operation in } } concurrentOperation.manualRetry = true + /// Later on your code concurrentOperation.retry() ``` +> [!CAUTION] +> If the `retry()` function is not called, you may block the entire queue. + +### Manually Finish an Operation + +By default the `Operation` will finish its job when the execution closure is completed. + +This means, if you have an asynchronous task insiede the closure, the `Operation` will finish before the task is completed. + +If you want to finish it manually, you can set the `manualFinish` property to `true` and call the `finish()` function when the task is completed. + +Call the `finish(success:)` function with `success` parameter to `true` or `false` to let the `Operation` know if the task was successful or not. If you don't explicitly set the `success` parameter, it will be set to `true`. + +```swift +let concurrentOperation = ConcurrentOperation { operation in + /// Your asynchonous task here +} +concurrentOperation.manualFinish = true + +/// Later on your code in your asynchronous task +concurrentOperation.finish(success: true) +``` + +> [!CAUTION] +> If you don't call the `finish()` function, your queue will be blocked and it will never ends. + ### 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 @@ -341,21 +315,26 @@ let schedule = Scheduler(deadline: .now(), repeating: .seconds(1)) { ``` 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. + /// 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. + +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. + +> [!TIP] +> Is recommend to use a `defer { semaphore.continue() }` right after the `Semaphore` creation and `wait()` call. ```swift let semaphore = Semaphore() @@ -365,11 +344,13 @@ defer { semaphore.continue() } ``` 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 { /// Your task here @@ -379,49 +360,21 @@ concurrentOperation.addToQueue(queue) semaphore.wait() ``` -### Queue State Restoration (Beta) -To enable the Queue Restoration feature you must use `ConcurrentOperation` with a unique (non-nil) `name` property. -Currently this feature allows you to save the current state (`OperationState`s) of your queue, like: `name`, `progress` and `dependencies`.
-The `progress` property allows to save the current state of the `Operation` progress. Update it constantly during the `Operation` execution.
-Call `Queuer.state(of: OperationQueue)` or `operationQueue.state()` to get the `QueueStateList` aka: Array of `OperationState`s.
-It's up to you save and retrieve this list, and create the queue correctly. - -Documentation -============= +## Changelog -Jazzy Generated [Documentation] - 100% Documented +To see what has changed in recent versions of Queuer, see the **[CHANGELOG.md](https://github.com/FabrizioBrancati/Queuer/blob/main/CHANGELOG.md)** file. -Changelog -========= - -To see what has changed in recent versions of Queuer, see the **[CHANGELOG.md](https://github.com/FabrizioBrancati/Queuer/blob/master/CHANGELOG.md)** file. - -Communication -============= +## Communication - If you need help, open an issue. - If you found a bug, open an issue. - If you have a feature request, open an issue. - If you want to contribute, see [Contributing](https://github.com/FabrizioBrancati/Queuer#contributing) section. -Contributing -============ - -See [CONTRIBUTING.md](https://github.com/FabrizioBrancati/Queuer/blob/master/.github/CONTRIBUTING.md) file. - -Author -====== - -**Fabrizio Brancati** - -[Website: https://www.fabriziobrancati.com](https://www.fabriziobrancati.com) -
-[Email: fabrizio.brancati@gmail.com](mailto:fabrizio.brancati@gmail.com) +## Contributing -License -======= +See [CONTRIBUTING.md](https://github.com/FabrizioBrancati/Queuer/blob/main/.github/CONTRIBUTING.md) file. -Queuer is available under the MIT license. See the **[LICENSE](https://github.com/FabrizioBrancati/Queuer/blob/master/LICENSE)** file for more info. +## License -[Documentation]: https://github.fabriziobrancati.com/documentation/Queuer/ -[✓]: Resources/Check.png +Queuer is available under the MIT license. See the **[LICENSE](https://github.com/FabrizioBrancati/Queuer/blob/main/LICENSE)** file for more info. diff --git a/Resources/Banner.png b/Resources/Banner.png deleted file mode 100644 index ff874fd..0000000 Binary files a/Resources/Banner.png and /dev/null differ diff --git a/Resources/Check.png b/Resources/Check.png deleted file mode 100644 index 27fb928..0000000 Binary files a/Resources/Check.png and /dev/null differ diff --git a/Resources/Icon-32.png b/Resources/Icon-32.png deleted file mode 100644 index 348fdb8..0000000 Binary files a/Resources/Icon-32.png and /dev/null differ diff --git a/Sources/Info.plist b/Sources/Info.plist deleted file mode 100644 index 6a210bb..0000000 --- a/Sources/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 2.1.1 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2017 - 2019 Fabrizio Brancati. - NSPrincipalClass - - UIRequiredDeviceCapabilities - - arm64 - - - diff --git a/Sources/Queuer.h b/Sources/Queuer.h deleted file mode 100644 index 5734a28..0000000 --- a/Sources/Queuer.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Queuer.h -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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; - -//! Project version number for Queuer. -FOUNDATION_EXPORT double QueuerVersionNumber; - -//! Project version string for Queuer. -FOUNDATION_EXPORT const unsigned char QueuerVersionString[]; diff --git a/Sources/Queuer/ConcurrentOperation.swift b/Sources/Queuer/ConcurrentOperation.swift index fd51a49..ed61a9e 100644 --- a/Sources/Queuer/ConcurrentOperation.swift +++ b/Sources/Queuer/ConcurrentOperation.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -31,12 +31,7 @@ import Foundation open class ConcurrentOperation: Operation { /// `Operation`'s execution block. public var executionBlock: ((_ operation: ConcurrentOperation) -> Void)? - - /// Set the `Operation` as asynchronous. - override open var isAsynchronous: Bool { - return true - } - + /// Set if the `Operation` is executing. private var _executing = false { willSet { @@ -46,12 +41,12 @@ open class ConcurrentOperation: Operation { didChangeValue(forKey: "isExecuting") } } - + /// Set if the `Operation` is executing. override open var isExecuting: Bool { return _executing } - + /// Set if the `Operation` is finished. private var _finished = false { willSet { @@ -61,94 +56,83 @@ open class ConcurrentOperation: Operation { didChangeValue(forKey: "isFinished") } } - + /// Set if the `Operation` is finished. override open var isFinished: Bool { return _finished } - - /// `Operation` progress, set it as many times as you like within the `Operation` execution. - /// Useful for Queue Restoration. - open var progress: Int = 0 { - didSet { - progress = progress < 100 ? (progress > 0 ? progress : 0) : 100 - } - } - - /// 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. - @available(*, deprecated, renamed: "success") - open var hasFailed: Bool { - return !success - } - + /// You should use `success` if you want the retry feature. /// Set it to `false` if the `Operation` has failed, otherwise `true`. /// Default is `true` to avoid retries. open var success = true - + /// Maximum allowed retries. /// Default are 3 retries. open var maximumRetries = 3 - + /// Current retry attempt. open private(set) 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 + internal var shouldRetry = true + /// Manually control the `finish()` call of the `Operation`. + /// If set to `true` it is the developer's responsibility to call the `finish()` method, + /// either by passing `false` or `true` to the function. + open var manualFinish = false + /// Creates the `Operation` with an execution block. /// /// - Parameters: - /// - name: Operation name, useful for Queue Restoration. It must be unique. + /// - name: Operation name. /// - executionBlock: Execution block. public init(name: String? = nil, executionBlock: ((_ operation: ConcurrentOperation) -> Void)? = nil) { super.init() - + self.name = name self.executionBlock = executionBlock } - + /// Start the `Operation`. override open func start() { _executing = true execute() } - + /// Retry function. /// It only works if `manualRetry` property has been set to `true`. open func retry() { - if manualRetry, shouldRetry, let executionBlock = executionBlock { + if manualRetry, shouldRetry, let executionBlock { executionBlock(self) - finish(success: success) + + if !manualFinish { + finish(success: success) + } } } - + /// Execute the `Operation`. - /// If `executionBlock` is set, it will be executed and also `finish()` will be called. + /// If `executionBlock` is set, it will be executed. open func execute() { - if let executionBlock = executionBlock { + if let executionBlock { while shouldRetry, !manualRetry { executionBlock(self) - finish(success: success) + + if !manualFinish { + finish(success: success) + } } - + retry() } } - - /// - Parameter hasFailed: Set it to `true` if the `Operation` has failed, otherwise `false`. - @available(*, deprecated, renamed: "finish(success:)") - open func finish(_ hasFailed: Bool) { - finish(success: !hasFailed) - } - + /// Notify the completion of asynchronous task and hence the completion of the `Operation`. /// Must be called when the `Operation` is finished. /// @@ -163,12 +147,14 @@ open class ConcurrentOperation: Operation { currentAttempt += 1 shouldRetry = true } + + self.success = success } - + /// Pause the current `Operation`, if it's supported. /// Must be overridden by a subclass to get a custom pause action. open func pause() {} - + /// Resume the current `Operation`, if it's supported. /// Must be overridden by a subclass to get a custom resume action. open func resume() {} @@ -180,7 +166,7 @@ public extension ConcurrentOperation { func addToSharedQueuer() { Queuer.shared.addOperation(self) } - + /// Adds the `Operation` to the custom queue. /// /// - Parameter queue: Custom queue where the `Operation` will be added. diff --git a/Sources/Queuer/GroupOperation.swift b/Sources/Queuer/GroupOperation.swift new file mode 100644 index 0000000..a26a458 --- /dev/null +++ b/Sources/Queuer/GroupOperation.swift @@ -0,0 +1,67 @@ +// +// ConcurrentOperation.swift +// Queuer +// +// MIT License +// +// Copyright (c) 2017 - 2024 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 + +/// It allows the creation of group `Operation`s by using it's `operations` array of `ConcurrentOperation`. +open class GroupOperation: ConcurrentOperation { + /// Private `OperationQueue` instance. + private let queue = OperationQueue() + + /// List of `ConcurrentOperation` that should be run in this `GroupOperation`. + public var operations: [ConcurrentOperation] = [] + + /// Flag to know if all `ConcurrentOperation` of this `GroupOperation` were successful. + public var allOperationsSucceeded: Bool { + return !operations.contains { !$0.success } + } + + /// Creates the `GroupOperation` with a completion handler. + /// Allows the execution of a block of `Operation`s with a completion handler that will be called + /// once all the operations are finished. + /// + /// Example: + /// + /// [A -> [[B & C & D] -> completionHandler] -> E] -> completionHandler + /// + /// - Parameters: + /// - operations: Array of ConcurrentOperation to be executed. + /// - completionHandler: Block that will be executed once all operations are over. + public init(_ operations: [ConcurrentOperation], completionHandler: (() -> Void)? = nil) { + super.init() + + self.operations = operations + self.completionBlock = completionHandler + } + + /// Execute the `Operation`. + /// The execution of a `GroupOperation` will always be considered successful. + /// Use the variable `allOperationsSucceeded` to know if an error occurred on an operation in the Group. + override open func execute() { + queue.addOperations(operations, waitUntilFinished: true) + finish(success: true) + } +} diff --git a/Sources/Queuer/OperationState.swift b/Sources/Queuer/OperationState.swift deleted file mode 100644 index 3010bc0..0000000 --- a/Sources/Queuer/OperationState.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// OperationState.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 - -/// `Operation` State class. -/// Used to save the `Operation` State. -/// This class allows to save the current queue state. -public class OperationState: Codable { - /// `Operation` name. - public var name: String - /// `Operation` progress. - public var progress: Int - /// `Operation` dependencies. It - public var dependencies: [String] - - /// Initialize an `OperationState`. - /// - /// - Parameters: - /// - name: `Operation` name. - /// - progress: `Operation` progress. - /// - dependencies: `Operation` dependencies. - public init(name: String, progress: Int, dependencies: [String]) { - self.name = name - self.progress = progress - self.dependencies = dependencies - } -} - -/// `OperationState` extension to allow custom print of the class. -extension OperationState: CustomStringConvertible { - public var description: String { - return """ - Operation Name: \(name) - Operation Progress: \(progress) - Operation Dependencies: \(dependencies) - """ - } -} diff --git a/Sources/Queuer/Queuer.swift b/Sources/Queuer/Queuer.swift index 1e7aebc..4f6ffc7 100644 --- a/Sources/Queuer/Queuer.swift +++ b/Sources/Queuer/Queuer.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -30,20 +30,20 @@ import Foundation public class Queuer { /// Shared Queuer. public static let shared = Queuer(name: "Queuer") - + /// Queuer `OperationQueue`. public let queue = OperationQueue() - + /// Total `Operation` count in queue. public var operationCount: Int { return queue.operationCount } - + /// `Operation`s currently in queue. public var operations: [Operation] { return queue.operations } - + /// The default service level to apply to `Operation`s executed using the queue. public var qualityOfService: QualityOfService { get { @@ -53,14 +53,14 @@ public class Queuer { queue.qualityOfService = newValue } } - + /// Returns if the queue is executing or is in pause. /// Call `resume()` to make it running. /// Call `pause()` to make to pause it. public var isExecuting: Bool { return !queue.isSuspended } - + /// Define the max concurrent `Operation`s count. public var maxConcurrentOperationCount: Int { get { @@ -70,46 +70,46 @@ public class Queuer { queue.maxConcurrentOperationCount = newValue } } - + /// Creates a new queue. /// /// - Parameters: /// - name: Custom queue name. /// - 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) { + public init(name: String, maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount, qualityOfService: QualityOfService = .default) { queue.name = name self.maxConcurrentOperationCount = maxConcurrentOperationCount 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 { if let concurrentOperation = operation as? ConcurrentOperation { concurrentOperation.pause() } } } - + /// Resume the queue. public func resume() { queue.isSuspended = false - + for operation in queue.operations { if let concurrentOperation = operation as? ConcurrentOperation { concurrentOperation.resume() } } } - + /// Blocks the current thread until all of the receiver’s queued and executing /// `Operation`s finish executing. public func waitUntilAllOperationsAreFinished() { @@ -127,45 +127,45 @@ public extension Queuer { func addOperation(_ operation: @escaping () -> Void) { queue.addOperation(operation) } - + /// Add an `Operation` to be executed asynchronously. /// /// - Parameter operation: `Operation` to be executed. func addOperation(_ operation: Operation) { queue.addOperation(operation) } - + /// Add an Array of chained `Operation`s. /// /// Example: /// - /// [A, B, C] = A -> B -> C -> completionHandler. + /// [A, B, C] = A -> B -> C -> completionHandler /// /// - Parameters: /// - operations: `Operation`s Array. - /// - completionHandler: Completion block to be exectuted when all `Operation`s + /// - completionHandler: Completion block to be executed when all `Operation`s /// are finished. func addChainedOperations(_ operations: [Operation], completionHandler: (() -> Void)? = nil) { for (index, operation) in operations.enumerated() { if index > 0 { operation.addDependency(operations[index - 1]) } - + addOperation(operation) } - + guard let completionHandler = completionHandler else { return } - + addCompletionHandler(completionHandler) } - + /// Add an Array of chained `Operation`s. /// /// Example: /// - /// [A, B, C] = A -> B -> C -> completionHandler. + /// [A, B, C] = A -> B -> C -> completionHandler /// /// - Parameters: /// - operations: `Operation`s list. @@ -174,7 +174,7 @@ public extension Queuer { func addChainedOperations(_ operations: Operation..., completionHandler: (() -> Void)? = nil) { addChainedOperations(operations, completionHandler: completionHandler) } - + /// Add a completion block to the queue. /// /// - Parameter completionHandler: Completion handler to be executed as last `Operation`. @@ -186,34 +186,3 @@ public extension Queuer { addOperation(completionOperation) } } - -// MARK: - Queue State Restoration - -/// `Queuer` extension with state restoration feature. -public extension Queuer { - /// `OperationState` array typealias. - typealias QueueStateList = [OperationState] - - /// Creates the queue state. - /// - /// - Returns: Returns the current queue state. - func state() -> QueueStateList { - return Queuer.state(of: queue) - } - - /// Creates the state of a given queue. - /// - /// - Parameter queue: State will be created starting from this `OperationQueue`. - /// - Returns: Returns the current queue state. - static func state(of queue: OperationQueue) -> QueueStateList { - var operations: QueueStateList = [] - - for operation in queue.operations { - if let concurrentOperation = operation as? ConcurrentOperation, let operationName = concurrentOperation.name { - operations.append(OperationState(name: operationName, progress: concurrentOperation.progress, dependencies: operation.dependencies.compactMap { $0.name })) - } - } - - return operations - } -} diff --git a/Sources/Queuer/Scheduler.swift b/Sources/Queuer/Scheduler.swift index a06c3bc..554e323 100644 --- a/Sources/Queuer/Scheduler.swift +++ b/Sources/Queuer/Scheduler.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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,7 @@ public struct Scheduler { public private(set) var qualityOfService: DispatchQoS /// Schedule handler. public private(set) var handler: (() -> Void)? - + /// Create a schedule. /// /// - Parameters: @@ -52,26 +52,22 @@ public struct Scheduler { 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() - } + if let handler { + timer.setEventHandler(qos: qualityOfService, handler: handler) timer.resume() } } - + /// Set the handler after schedule creation. /// /// - Parameter handler: Closure handler. public mutating func setHandler(_ handler: @escaping () -> Void) { self.handler = handler - - timer.setEventHandler(qos: qualityOfService) { - handler() - } + + timer.setEventHandler(qos: qualityOfService, handler: handler) timer.resume() } } diff --git a/Sources/Queuer/Semaphore.swift b/Sources/Queuer/Semaphore.swift index 233df32..7c038f6 100644 --- a/Sources/Queuer/Semaphore.swift +++ b/Sources/Queuer/Semaphore.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -31,7 +31,7 @@ import Foundation public struct Semaphore { /// Private `DispatchSemaphore`. private let semaphore: DispatchSemaphore - + /// Creates new counting semaphore with an initial value. /// Passing zero for the value is useful for when two threads need to reconcile /// the completion of a particular event. Passing a value greater than zero is @@ -43,7 +43,7 @@ public struct Semaphore { public init(poolSize: Int = 0) { semaphore = DispatchSemaphore(value: poolSize) } - + /// Wait for a `continue` function call. /// /// - Parameter timeout: The timeout `DispatchTime`. Default is `.distantFuture`. @@ -52,7 +52,7 @@ public struct Semaphore { 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. /// /// - Returns: Returns non-zero if a thread is woken. Otherwise, zero is returned. diff --git a/Sources/Queuer/SynchronousOperation.swift b/Sources/Queuer/SynchronousOperation.swift deleted file mode 100644 index 52fd21d..0000000 --- a/Sources/Queuer/SynchronousOperation.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// SynchronousOperation.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 - -/// 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 let semaphore = Semaphore() - - /// Set the `Operation` as synchronous. - override public var isAsynchronous: Bool { - return false - } - - /// Notify the completion of synchronous task and hence the completion of the `Operation`. - /// Must be called when the `Operation` is finished. - /// - /// - Parameter success: Set it to `false` if the `Operation` has failed, otherwise `true`. - /// Default is `true`. - override public func finish(success: Bool = true) { - super.finish(success: success) - - semaphore.continue() - } - - /// Advises the `Operation` object that it should stop executing its task. - override public func cancel() { - super.cancel() - - semaphore.continue() - } - - /// Execute the `Operation`. - /// If `executionBlock` is set, it will be executed and also `finish()` will be called. - override public func execute() { - super.execute() - - semaphore.wait() - } -} diff --git a/Tests/Info.plist b/Tests/Info.plist deleted file mode 100644 index a5d6aeb..0000000 --- a/Tests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 2.1.1 - CFBundleVersion - 1 - - diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift deleted file mode 100644 index 8398df0..0000000 --- a/Tests/LinuxMain.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// LinuxMain.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 - -#if os(Linux) || os(FreeBSD) - @testable import QueuerTests - - XCTMain( - [ - testCase(ConcurrentOperationTests.allTests), - testCase(OperationStateTests.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 deleted file mode 100644 index 3fbe298..0000000 --- a/Tests/QueuerTests/ConcurrentOperationTests+XCTest.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// ConcurrentOperationTests+XCTest.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 { - static var allTests: [(String, (ConcurrentOperationTests) -> () throws -> Void)] { - return [ - ("testProgress", testProgress), - ("testInitWithExecutionBlock", testInitWithExecutionBlock), - ("testIsAsynchronous", testIsAsynchronous), - ("testAddToSharedQueuer", testAddToSharedQueuer), - ("testAddToQueue", testAddToQueue), - ("testSimpleRetry", testSimpleRetry), - ("testChainedRetry", testChainedRetry), - ("testCanceledChainedRetry", testCanceledChainedRetry) - ] - } -} diff --git a/Tests/QueuerTests/ConcurrentOperationTests.swift b/Tests/QueuerTests/ConcurrentOperationTests.swift index 3fb40d5..0e459d6 100644 --- a/Tests/QueuerTests/ConcurrentOperationTests.swift +++ b/Tests/QueuerTests/ConcurrentOperationTests.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -24,67 +24,48 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -@testable import Queuer +import Queuer import XCTest -internal class ConcurrentOperationTests: XCTestCase { - internal func testProgress() { - let concurrentOperation = ConcurrentOperation() - - concurrentOperation.progress = 1000 - XCTAssertTrue(concurrentOperation.progress == 100) - - concurrentOperation.progress = -1000 - XCTAssertTrue(concurrentOperation.progress == 0) - - concurrentOperation.progress = 26 - XCTAssertTrue(concurrentOperation.progress == 26) - } - - internal func testInitWithExecutionBlock() { +final class ConcurrentOperationTests: XCTestCase { + func testInitWithExecutionBlock() { let queue = Queuer(name: "ConcurrentOperationTestInitWithExecutionBlock") - + let testExpectation = expectation(description: "Init With Execution Block") - + let concurrentOperation = ConcurrentOperation { _ in testExpectation.fulfill() } concurrentOperation.addToQueue(queue) - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) } } - - internal func testIsAsynchronous() { - let concurrentOperation = ConcurrentOperation() - - XCTAssertTrue(concurrentOperation.isAsynchronous) - } - - internal func testAddToSharedQueuer() { + + func testAddToSharedQueuer() { let concurrentOperation = ConcurrentOperation() concurrentOperation.addToSharedQueuer() - + XCTAssertEqual(Queuer.shared.operationCount, 1) XCTAssertEqual(Queuer.shared.operations, [concurrentOperation]) } - - internal func testAddToQueue() { + + func testAddToQueue() { let queue = Queuer(name: "ConcurrentOperationTestAddToQueuer") - + let concurrentOperation = ConcurrentOperation() concurrentOperation.addToQueue(queue) - + XCTAssertEqual(queue.operationCount, 1) XCTAssertEqual(queue.operations, [concurrentOperation]) } - - internal func testSimpleRetry() { + + func testSimpleRetry() { let queue = Queuer(name: "ConcurrentOperationTestSimpleRetry") - + let testExpectation = expectation(description: "Simple Retry") - + let concurrentOperation = ConcurrentOperation { operation in operation.success = false } @@ -94,19 +75,19 @@ internal class ConcurrentOperationTests: XCTestCase { } } concurrentOperation.addToQueue(queue) - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertFalse(concurrentOperation.success) XCTAssertEqual(concurrentOperation.currentAttempt, 3) } } - - internal func testChainedRetry() { + + 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) @@ -120,18 +101,18 @@ internal class ConcurrentOperationTests: XCTestCase { order.append(2) testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2]) } } - - internal func testCanceledChainedRetry() { + + 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) @@ -149,79 +130,239 @@ internal class ConcurrentOperationTests: XCTestCase { order.append(2) testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(order, [0, 0, 0, 2]) } } - - #if !os(Linux) - internal func testChainedManualRetry() { - let queue = Queuer(name: "ConcurrentOperationTestChainedManualRetry") - let testExpectation = expectation(description: "Chained Manual Retry") - var order: [Int] = [] - - let concurrentOperation1 = ConcurrentOperation(name: "concurrentOperation1") { operation in - operation.success = false - order.append(0) - } - concurrentOperation1.manualRetry = true - - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { - concurrentOperation1.retry() - } - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4)) { - concurrentOperation1.retry() - } - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(6)) { - concurrentOperation1.retry() - } - - let concurrentOperation2 = ConcurrentOperation(name: "concurrentOperation2") { operation in - operation.success = false - order.append(1) - } - - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { - queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { - order.append(2) - testExpectation.fulfill() - } - } - - waitForExpectations(timeout: 10) { error in - XCTAssertNil(error) - XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2]) - } + + func testChainedManualRetry() { + let queue = Queuer(name: "ConcurrentOperationTestChainedManualRetry") + let testExpectation = expectation(description: "Chained Manual Retry") + var order: [Int] = [] + + let concurrentOperation1 = ConcurrentOperation(name: "concurrentOperation1") { operation in + operation.success = false + order.append(0) } - - 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.success = false - } - concurrentOperation1.manualRetry = true - - let concurrentOperation2 = ConcurrentOperation { _ in - order.append(1) - } + concurrentOperation1.manualRetry = true + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { + concurrentOperation1.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4)) { + concurrentOperation1.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(6)) { + concurrentOperation1.retry() + } + + let concurrentOperation2 = ConcurrentOperation(name: "concurrentOperation2") { operation in + operation.success = false + order.append(1) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { order.append(2) - } - - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) { testExpectation.fulfill() } - - waitForExpectations(timeout: 10) { error in - XCTAssertNil(error) - XCTAssertEqual(order, [0]) + } + + waitForExpectations(timeout: 10) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0, 0, 0, 1, 1, 1, 2]) + } + } + + 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.success = false + } + concurrentOperation1.manualRetry = true + + let concurrentOperation2 = ConcurrentOperation { _ in + order.append(1) + } + queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { + order.append(2) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 10) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0]) + } + } + + func testConcurrentOperation() { + let queue = Queuer(name: "ConcurrentOperation") + let testExpectation = expectation(description: "Concurrent Operation") + var testString = "" + + let concurrentOperation1 = ConcurrentOperation { _ in + testString = "Tested1" + } + let concurrentOperation2 = ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 2) + testString = "Tested2" + + testExpectation.fulfill() + } + concurrentOperation1.addToQueue(queue) + concurrentOperation2.addToQueue(queue) + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(testString, "Tested2") + } + } + + func testConcurrentOperationOnSharedQueuer() { + let testExpectation = expectation(description: "Concurrent Operation") + var testString = "" + + let concurrentOperation1 = ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 1.5) + testString = "Tested1" + + testExpectation.fulfill() + } + let concurrentOperation2 = ConcurrentOperation { _ in + testString = "Tested2" + } + Queuer.shared.maxConcurrentOperationCount = 2 + concurrentOperation2.addToSharedQueuer() + concurrentOperation1.addToSharedQueuer() + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(testString, "Tested1") + } + } + + func testConcurrentOperationRetry() { + let queue = Queuer(name: "ConcurrentOperationRetry") + let testExpectation = expectation(description: "Concurrent Operation Retry") + var order: [Int] = [] + + let concurrentOperation1 = ConcurrentOperation { operation in + Thread.sleep(forTimeInterval: 2.5) + order.append(0) + operation.success = false + + if operation.currentAttempt == 3 { + testExpectation.fulfill() } } - #endif + concurrentOperation1.addToQueue(queue) + + let concurrentOperation2 = ConcurrentOperation { _ in + order.append(1) + } + concurrentOperation2.addToQueue(queue) + + waitForExpectations(timeout: 10) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [1, 0, 0, 0]) + } + } + + func testCancel() { + let queue = Queuer(name: "TestCancel", maxConcurrentOperationCount: 1) + let testExpectation = expectation(description: "Cancel") + var testString = "" + + let deadline = DispatchTime.now() + .seconds(2) + DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) { + queue.cancelAll() + testExpectation.fulfill() + } + + let concurrentOperation1 = ConcurrentOperation { _ in + testString = "Tested1" + Thread.sleep(forTimeInterval: 4) + } + let concurrentOperation2 = ConcurrentOperation { _ in + testString = "Tested2" + } + concurrentOperation1.addToQueue(queue) + concurrentOperation2.addToQueue(queue) + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(testString, "Tested1") + } + } + + func testManualFinish() { + let queue = Queuer(name: "ManualFinish") + let testExpectation = expectation(description: "Manual Finish") + + let concurrentOperation = ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 2) + } + concurrentOperation.manualFinish = true + + concurrentOperation.addToQueue(queue) + + let deadline = DispatchTime.now() + .seconds(4) + DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) { + XCTAssertFalse(concurrentOperation.isFinished) + concurrentOperation.finish() + testExpectation.fulfill() + } + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertTrue(concurrentOperation.isFinished) + } + } + + func testChainedManualRetryAndManualFinish() { + let queue = Queuer(name: "ConcurrentOperationTestChainedManualRetryAndManualFinish") + let testExpectation = expectation(description: "Chained Manual Retry And Manual Finish") + var order: [Int] = [] + + let concurrentOperation = ConcurrentOperation(name: "concurrentOperation1") { operation in + operation.success = false + order.append(0) + } + concurrentOperation.manualRetry = true + concurrentOperation.manualFinish = true + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { + concurrentOperation.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4)) { + concurrentOperation.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(6)) { + concurrentOperation.retry() + } + + concurrentOperation.addToQueue(queue) + + let deadline = DispatchTime.now() + .seconds(4) + DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) { + XCTAssertFalse(concurrentOperation.isFinished) + concurrentOperation.finish() + testExpectation.fulfill() + } + + waitForExpectations(timeout: 10) { error in + XCTAssertNil(error) + XCTAssertEqual(order, [0, 0, 0]) + XCTAssertTrue(concurrentOperation.isFinished) + } + } } diff --git a/Tests/QueuerTests/GroupOperationTests.swift b/Tests/QueuerTests/GroupOperationTests.swift new file mode 100644 index 0000000..85cbf28 --- /dev/null +++ b/Tests/QueuerTests/GroupOperationTests.swift @@ -0,0 +1,197 @@ +// +// GroupOperationTests.swift +// Queuer +// +// MIT License +// +// Copyright (c) 2017 - 2024 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 Queuer +import XCTest + +final class GroupOperationTests: XCTestCase { + func testGroupOperations() { + var order: [String] = [] + let testExpectation = expectation(description: "GroupOperations") + let queue = Queuer(name: "Group Operations") + + let groupOperation1 = GroupOperation( + [ + ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 2) + order.append("1") + }, + ConcurrentOperation { _ in + order.append("2") + } + ] + ) { + order.append("3") + } + + let groupOperation2 = GroupOperation( + [ + ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 2) + order.append("4") + }, + ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 4) + order.append("5") + } + ] + ) { + order.append("6") + } + + let groupOperation3 = ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 2) + order.append("7") + } + + queue.addChainedOperations([groupOperation1, groupOperation2, groupOperation3]) { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 14) { error in + XCTAssertTrue(groupOperation1.allOperationsSucceeded) + XCTAssertNil(error) + XCTAssertEqual(order, ["2", "1", "3", "4", "5", "6", "7"]) + } + } + + func testGroupOperationsWithInnerChainedRetry() { + var order: [String] = [] + let testExpectation = expectation(description: "GroupOperationsWithInnerChainedRetry") + let queue = Queuer(name: "Group Operations Chained Retry") + + let groupOperation1 = GroupOperation( + [ + ConcurrentOperation { _ in + order.append("1") + }, + ConcurrentOperation { operation in + Thread.sleep(forTimeInterval: 1) + order.append("2") + operation.success = false + } + ] + ) + + let groupOperation2 = ConcurrentOperation { _ in + order.append("3") + } + + queue.addChainedOperations([groupOperation1, groupOperation2]) { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 8) { error in + XCTAssertNil(error) + XCTAssertEqual(order, ["1", "2", "2", "2", "3"]) + } + } + + func testGroupOperationsWithCancelledInnerChainedRetry() { + let queue = Queuer(name: "GroupOperationsWithCancelledInnerChainedRetry") + let testExpectation = expectation(description: "Group Operations Cancelled Inner Chained Retry") + var order: [String] = [] + + let groupOperation1 = GroupOperation( + [ + ConcurrentOperation { operation in + Thread.sleep(forTimeInterval: 1) + order.append("1") + operation.success = false + }, + ConcurrentOperation { operation in + operation.cancel() + guard !operation.isCancelled else { + return + } + order.append("2") + operation.success = false + } + ] + ) + + let groupOperation2 = ConcurrentOperation { _ in + order.append("3") + } + + queue.addChainedOperations([groupOperation1, groupOperation2]) { + testExpectation.fulfill() + } + + waitForExpectations(timeout: 6) { error in + XCTAssertNil(error) + XCTAssertEqual(order, ["1", "1", "1", "3"]) + } + } + + func testGroupOperationsWithInnerChainedManualRetry() { + let queue = Queuer(name: "GroupOperationsWithInnerChainedManualRetry") + let testExpectation = expectation(description: "Group Operations Inner Chained Manual Retry") + var order: [String] = [] + + let concurrentOperation1 = ConcurrentOperation { operation in + order.append("1") + operation.success = false + } + concurrentOperation1.manualRetry = true + + let concurrentOperation2 = ConcurrentOperation { operation in + Thread.sleep(forTimeInterval: 1) + order.append("2") + operation.success = false + } + concurrentOperation2.manualRetry = true + + let groupOperation1 = GroupOperation([concurrentOperation1, concurrentOperation2]) + + let groupOperation2 = ConcurrentOperation { _ in + order.append("3") + } + + queue.addChainedOperations([groupOperation1, groupOperation2]) { + testExpectation.fulfill() + } + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { + concurrentOperation1.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4)) { + concurrentOperation2.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) { + concurrentOperation2.retry() + } + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(6)) { + concurrentOperation1.retry() + } + + waitForExpectations(timeout: 8) { error in + XCTAssertNil(error) + XCTAssertEqual(order, ["1", "2", "1", "2", "2", "1", "3"]) + } + } +} diff --git a/Tests/QueuerTests/OperationStateTests+XCTest.swift b/Tests/QueuerTests/OperationStateTests+XCTest.swift deleted file mode 100644 index 94497fd..0000000 --- a/Tests/QueuerTests/OperationStateTests+XCTest.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// OperationStateTests+XCTest.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 OperationStateTests { - static var allTests: [(String, (OperationStateTests) -> () throws -> Void)] { - return [ - ("testInitOperationState", testInitOperationState), - ("testCustomDescription", testCustomDescription), - ("testEncodeDecode", testEncodeDecode) - ] - } -} diff --git a/Tests/QueuerTests/OperationStateTests.swift b/Tests/QueuerTests/OperationStateTests.swift deleted file mode 100644 index 4ddae67..0000000 --- a/Tests/QueuerTests/OperationStateTests.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// OperationStateTests.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 OperationStateTests: XCTestCase { - internal func testInitOperationState() { - let operationState = OperationState(name: "Test", progress: 50, dependencies: ["Test2"]) - - XCTAssertEqual(operationState.name, "Test") - XCTAssertEqual(operationState.progress, 50) - XCTAssertEqual(operationState.dependencies, ["Test2"]) - } - - internal func testCustomDescription() { - let operationState = OperationState(name: "Test", progress: 50, dependencies: ["Test2"]) - let correctDescription = """ - Operation Name: Test - Operation Progress: 50 - Operation Dependencies: ["Test2"] - """ - - XCTAssertEqual(operationState.description, correctDescription) - } - - internal func testEncodeDecode() { - var operationState = OperationState(name: "Test", progress: 50, dependencies: ["Test2"]) - - let encoder = JSONEncoder() - do { - let data = try encoder.encode(operationState) - let decoder = JSONDecoder() - operationState = try decoder.decode(OperationState.self, from: data) - - XCTAssertEqual(operationState.name, "Test") - XCTAssertEqual(operationState.progress, 50) - XCTAssertEqual(operationState.dependencies, ["Test2"]) - } catch { - XCTFail("Failed encoding or decoding") - } - } -} diff --git a/Tests/QueuerTests/QueuerTests+XCTest.swift b/Tests/QueuerTests/QueuerTests+XCTest.swift deleted file mode 100644 index 3e7977a..0000000 --- a/Tests/QueuerTests/QueuerTests+XCTest.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// QueuerTests+XCTest.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 { - 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 9972950..b1ea675 100644 --- a/Tests/QueuerTests/QueuerTests.swift +++ b/Tests/QueuerTests/QueuerTests.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -25,114 +25,166 @@ // SOFTWARE. import Dispatch -@testable import Queuer +import Queuer import XCTest -internal class QueuerTests: XCTestCase { - internal func testOperationCount() { +final class QueuerTests: XCTestCase { + #if !os(Linux) + func testOperationCount() { let queue = Queuer(name: "QueuerTestOperationCount") let testExpectation = expectation(description: "Operation Count") - + XCTAssertEqual(queue.operationCount, 0) - + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testExpectation.fulfill() } concurrentOperation.addToQueue(queue) XCTAssertEqual(queue.operationCount, 1) - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(queue.operationCount, 0) } } - - internal func testOperations() { + + func testOperations() { let queue = Queuer(name: "QueuerTestOperations") let testExpectation = expectation(description: "Operations") - + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testExpectation.fulfill() } queue.addOperation(concurrentOperation) XCTAssertTrue(queue.operations.contains(concurrentOperation)) - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertFalse(queue.operations.contains(concurrentOperation)) } } - - internal func testMaxConcurrentOperationCount() { + #endif + + func testMaxConcurrentOperationCount() { let queue = Queuer(name: "QueuerTestMaxConcurrentOperationCount") - + queue.maxConcurrentOperationCount = 10 - + XCTAssertEqual(queue.maxConcurrentOperationCount, 10) } - - internal func testQualityOfService() { + + #if !os(Linux) + func testMaxConcurrentOperationCountSetToOne() { + let testExpectation = expectation(description: "Max Concurrent Operation Count Set To One") + var testString = "" + + let concurrentOperation1 = ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 3.5) + testString = "Tested1" + + testExpectation.fulfill() + } + let concurrentOperation2 = ConcurrentOperation { _ in + testString = "Tested2" + } + Queuer.shared.maxConcurrentOperationCount = 1 + Queuer.shared.addOperation(concurrentOperation1) + Queuer.shared.addOperation(concurrentOperation2) + + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(testString, "Tested2") + } + } + #endif + + func testMaxConcurrentOperationCountSetToTwo() { + let testExpectation = expectation(description: "Max Concurrent Operation Count Set To Two") + var testString = "" + + let concurrentOperation1 = ConcurrentOperation { _ in + Thread.sleep(forTimeInterval: 3) + testString = "Tested1" + + testExpectation.fulfill() + } + let concurrentOperation2 = ConcurrentOperation { _ in + testString = "Tested2" + } + Queuer.shared.maxConcurrentOperationCount = 2 + Queuer.shared.addOperation(concurrentOperation2) + Queuer.shared.addOperation(concurrentOperation1) + + waitForExpectations(timeout: 5) { error in + XCTAssertNil(error) + XCTAssertEqual(testString, "Tested1") + } + } + + func testQualityOfService() { let queue = Queuer(name: "QueuerTestMaxConcurrentOperationCount") - + queue.qualityOfService = .background - + XCTAssertEqual(queue.qualityOfService, .background) } - - internal func testInitWithNameMaxConcurrentOperationCount() { + + func testInitWithNameMaxConcurrentOperationCount() { let queueName = "TestInitWithNameMaxConcurrentOperationCount" let queue = Queuer(name: queueName, maxConcurrentOperationCount: 10) - + XCTAssertEqual(queue.queue.name, queueName) XCTAssertEqual(queue.queue.maxConcurrentOperationCount, 10) } - - internal func testInitWithNameMaxConcurrentOperationCountQualityOfService() { + + func testInitWithNameMaxConcurrentOperationCountQualityOfService() { let queueName = "TestInitWithNameMaxConcurrentOperationCountQualityOfService" let queue = Queuer(name: queueName, maxConcurrentOperationCount: 10, qualityOfService: .background) - + XCTAssertEqual(queue.queue.name, queueName) XCTAssertEqual(queue.queue.maxConcurrentOperationCount, 10) XCTAssertEqual(queue.queue.qualityOfService, .background) } - - internal func testAddOperationBlock() { + + func testAddOperationBlock() { let queue = Queuer(name: "QueuerTestAddOperationBlock") let testExpectation = expectation(description: "Add Operation Block") - + queue.addOperation { XCTAssertEqual(queue.operationCount, 1) testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) } } - - internal func testAddOperation() { + + func testAddOperation() { let queue = Queuer(name: "QueuerTestAddOperation") let testExpectation = expectation(description: "Add Operation") - + let concurrentOperation = ConcurrentOperation { _ in XCTAssertEqual(queue.operationCount, 1) + Thread.sleep(forTimeInterval: 0.5) testExpectation.fulfill() } queue.addOperation(concurrentOperation) - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(queue.operationCount, 0) } } - - internal func testAddOperations() { + + func testAddOperations() { let queue = Queuer(name: "QueuerTestAddOperations") let testExpectation = expectation(description: "Add Operations") var check = 0 - + let concurrentOperation1 = ConcurrentOperation { _ in check += 1 } @@ -140,24 +192,27 @@ internal class QueuerTests: XCTestCase { check += 1 } queue.addOperation(concurrentOperation1) + XCTAssertEqual(queue.operationCount, 1) + queue.addOperation(concurrentOperation2) - + XCTAssertEqual(queue.operationCount, 2) + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(queue.operationCount, 0) XCTAssertEqual(check, 2) } } - - internal func testAddChainedOperations() { + + func testAddChainedOperations() { let queue = Queuer(name: "QueuerTestAddChainedOperations") let testExpectation = expectation(description: "Add Chained Operations") var order: [Int] = [] - + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) @@ -169,18 +224,18 @@ internal class QueuerTests: XCTestCase { order.append(2) testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(order, [0, 1, 2]) } } - - internal func testAddChainedOperationsList() { + + func testAddChainedOperationsList() { let queue = Queuer(name: "QueuerTestAddChainedOperationsList") let testExpectation = expectation(description: "Add Chained Operations List") var order: [Int] = [] - + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) @@ -192,82 +247,83 @@ internal class QueuerTests: XCTestCase { order.append(2) testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(order, [0, 1, 2]) } } - - internal func testAddChainedOperationsEmpty() { + + func testAddChainedOperationsEmpty() { let queue = Queuer(name: "QueuerTestAddChainedOperationsEmpty") let testExpectation = expectation(description: "Add Chained Operations Empty") - + queue.addChainedOperations([]) { testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(queue.operationCount, 0) } } - - internal func testAddChainedOperationsWithoutCompletion() { + + func testAddChainedOperationsWithoutCompletion() { let queue = Queuer(name: "QueuerTestAddChainedOperationsWithoutCompletion") let testExpectation = expectation(description: "Add Chained Operations Without Completion") var order: [Int] = [] - + let concurrentOperation1 = ConcurrentOperation { _ in order.append(0) } let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) + Thread.sleep(forTimeInterval: 0.5) testExpectation.fulfill() } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(queue.operationCount, 0) XCTAssertEqual(order, [0, 1]) } } - - internal func testCancelAll() { + + func testCancelAll() { let queue = Queuer(name: "QueuerTestCancellAll") let testExpectation = expectation(description: "Cancell All Operations") var order: [Int] = [] - - let concurrentOperation1 = SynchronousOperation { _ in + + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) } - let concurrentOperation2 = SynchronousOperation { _ in + let concurrentOperation2 = ConcurrentOperation { _ in order.append(1) } queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { order.append(2) } - + queue.cancelAll() - + let deadline = DispatchTime.now() + .milliseconds(500) DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) { testExpectation.fulfill() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertNotEqual(order.count, 3) } } - - internal func testPauseAndResume() { + + func testPauseAndResume() { let queue = Queuer(name: "QueuerTestPauseAndResume") let testExpectation = expectation(description: "Pause and Resume") var order: [Int] = [] - + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) @@ -278,28 +334,29 @@ internal class QueuerTests: XCTestCase { queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { order.append(2) } - + queue.pause() - + XCTAssertLessThanOrEqual(queue.operationCount, 3) testExpectation.fulfill() - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertFalse(queue.isExecuting) XCTAssertLessThanOrEqual(queue.operationCount, 3) XCTAssertNotEqual(order, [0, 1, 2]) - + queue.resume() XCTAssertTrue(queue.isExecuting) } } - - internal func testWaitUnitlAllOperationsAreFinished() { + + #if !os(Linux) + func testWaitUnitlAllOperationsAreFinished() { let queue = Queuer(name: "QueuerTestWaitUnitlAllOperationsAreFinished") let testExpectation = expectation(description: "Wait Unitl All Operations Are Finished") var order: [Int] = [] - + let concurrentOperation1 = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) order.append(0) @@ -310,58 +367,22 @@ internal class QueuerTests: XCTestCase { queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { order.append(2) } - + queue.waitUntilAllOperationsAreFinished() - + XCTAssertEqual(order, [0, 1, 2]) XCTAssertLessThanOrEqual(queue.operationCount, 3) testExpectation.fulfill() - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertTrue(queue.isExecuting) XCTAssertLessThanOrEqual(queue.operationCount, 3) XCTAssertEqual(order, [0, 1, 2]) - + queue.resume() XCTAssertTrue(queue.isExecuting) } } - - #if !os(Linux) - internal func testQueueState() { - let queue = Queuer(name: "QueuerTestPauseAndResume") - let testExpectation = expectation(description: "Pause and Resume") - var state: Queuer.QueueStateList = [] - - let concurrentOperation1 = ConcurrentOperation(name: "Test1") { operation in - operation.progress = 50 - Thread.sleep(forTimeInterval: 4) - } - let concurrentOperation2 = ConcurrentOperation(name: "Test2") { _ in - Thread.sleep(forTimeInterval: 2) - } - queue.addChainedOperations([concurrentOperation1, concurrentOperation2]) { - testExpectation.fulfill() - } - - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { - state = queue.state() - } - - waitForExpectations(timeout: 10) { error in - XCTAssertNil(error) - - XCTAssertEqual(state.count, 2) - if state.count >= 2 { - XCTAssertEqual(state[0].name, "Test1") - XCTAssertEqual(state[0].progress, 50) - XCTAssertEqual(state[0].dependencies, []) - XCTAssertEqual(state[1].name, "Test2") - XCTAssertEqual(state[1].progress, 0) - XCTAssertEqual(state[1].dependencies, ["Test1"]) - } - } - } #endif } diff --git a/Tests/QueuerTests/SchedulerTests+XCTest.swift b/Tests/QueuerTests/SchedulerTests+XCTest.swift deleted file mode 100644 index 0cdcbe7..0000000 --- a/Tests/QueuerTests/SchedulerTests+XCTest.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// SchedulerTests+XCTest.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 { - static var allTests: [(String, (SchedulerTests) -> () throws -> Void)] { - return [ - ("testInitWithoutHandler", testInitWithoutHandler), - ("testInitWithHandler", testInitWithHandler), - ("testCancel", testCancel) - ] - } -} diff --git a/Tests/QueuerTests/SchedulerTests.swift b/Tests/QueuerTests/SchedulerTests.swift index 1950169..83d7774 100644 --- a/Tests/QueuerTests/SchedulerTests.swift +++ b/Tests/QueuerTests/SchedulerTests.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -25,65 +25,68 @@ // SOFTWARE. import Dispatch -@testable import Queuer +import Queuer import XCTest -internal class SchedulerTests: XCTestCase { - internal func testInitWithoutHandler() { +final class SchedulerTests: XCTestCase { + #if !os(Linux) + 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() } - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(order, [0, 0, 0, 0]) + schedule.timer.cancel() } } - - internal func testInitWithHandler() { + + 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: 5) { error in XCTAssertNil(error) XCTAssertEqual(order, [0]) schedule.timer.cancel() } } - - internal func testCancel() { + + 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]) } } + #endif } diff --git a/Tests/QueuerTests/SemaphoreTests+XCTest.swift b/Tests/QueuerTests/SemaphoreTests+XCTest.swift deleted file mode 100644 index f0d0ffc..0000000 --- a/Tests/QueuerTests/SemaphoreTests+XCTest.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// SemaphoreTests+XCTest.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 { - 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 f55bb4a..1ecb373 100644 --- a/Tests/QueuerTests/SemaphoreTests.swift +++ b/Tests/QueuerTests/SemaphoreTests.swift @@ -4,7 +4,7 @@ // // MIT License // -// Copyright (c) 2017 - 2019 Fabrizio Brancati +// Copyright (c) 2017 - 2024 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 @@ -24,49 +24,51 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -@testable import Queuer +import Queuer import XCTest -internal class SemaphoreTests: XCTestCase { - internal func testWithSemaphore() { +final class SemaphoreTests: XCTestCase { + #if !os(Linux) + func testWithSemaphore() { let semaphore = Semaphore() let queue = Queuer(name: "SemaphoreTestWithSemaphore") let testExpectation = expectation(description: "With Semaphore") var testString = "" - + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testString = "Tested" semaphore.continue() } concurrentOperation.addToQueue(queue) - + semaphore.wait() XCTAssertEqual(testString, "Tested") testExpectation.fulfill() - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) } } - - internal func testWithoutSemaphore() { + + func testWithoutSemaphore() { let queue = Queuer(name: "SemaphoreTestWithoutSemaphore") let testExpectation = expectation(description: "Without Semaphore") var testString = "" - + let concurrentOperation = ConcurrentOperation { _ in Thread.sleep(forTimeInterval: 2) testString = "Tested" testExpectation.fulfill() } concurrentOperation.addToQueue(queue) - + XCTAssertEqual(testString, "") - + waitForExpectations(timeout: 5) { error in XCTAssertNil(error) XCTAssertEqual(testString, "Tested") } } + #endif } diff --git a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift b/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift deleted file mode 100644 index c59df13..0000000 --- a/Tests/QueuerTests/SynchronousOperationTests+XCTest.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// SynchronousOperationTests+XCTest.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 { - static var allTests: [(String, (SynchronousOperationTests) -> () throws -> Void)] { - return [ - ("testSynchronousOperation", testSynchronousOperation), - ("testSynchronousOperationOnSharedQueuer", testSynchronousOperationOnSharedQueuer) - ] - } -} diff --git a/Tests/QueuerTests/SynchronousOperationTests.swift b/Tests/QueuerTests/SynchronousOperationTests.swift deleted file mode 100644 index f6bb190..0000000 --- a/Tests/QueuerTests/SynchronousOperationTests.swift +++ /dev/null @@ -1,145 +0,0 @@ -// -// SynchronousOperationTests.swift -// Queuer -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 SynchronousOperationTests: XCTestCase { - internal func testSynchronousOperation() { - let queue = Queuer(name: "SynchronousOperationTestSynchronousOperation") - let testExpectation = expectation(description: "Synchronous Operation") - var testString = "" - - let synchronousOperation1 = SynchronousOperation { _ in - testString = "Tested1" - } - let synchronousOperation2 = SynchronousOperation { _ in - Thread.sleep(forTimeInterval: 2) - testString = "Tested2" - - testExpectation.fulfill() - } - synchronousOperation1.addToQueue(queue) - synchronousOperation2.addToQueue(queue) - - XCTAssertFalse(synchronousOperation1.isAsynchronous) - XCTAssertFalse(synchronousOperation2.isAsynchronous) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - XCTAssertEqual(testString, "Tested2") - } - } - - internal func testSynchronousOperationOnSharedQueuer() { - let testExpectation = expectation(description: "Synchronous Operation") - var testString = "" - - let synchronousOperation1 = SynchronousOperation { _ in - testString = "Tested1" - } - let synchronousOperation2 = SynchronousOperation { _ in - Thread.sleep(forTimeInterval: 2) - testString = "Tested2" - - testExpectation.fulfill() - } - synchronousOperation1.addToSharedQueuer() - synchronousOperation2.addToSharedQueuer() - - XCTAssertFalse(synchronousOperation1.isAsynchronous) - XCTAssertFalse(synchronousOperation2.isAsynchronous) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - XCTAssertEqual(testString, "Tested2") - } - } - - #if !os(Linux) - 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: 2.5) - order.append(0) - operation.success = false - - if operation.currentAttempt == 3 { - testExpectation.fulfill() - } - } - synchronousOperation1.addToQueue(queue) - - let synchronousOperation2 = SynchronousOperation { _ in - order.append(1) - } - synchronousOperation2.addToQueue(queue) - - XCTAssertFalse(synchronousOperation1.isAsynchronous) - XCTAssertFalse(synchronousOperation2.isAsynchronous) - - waitForExpectations(timeout: 10) { error in - XCTAssertNil(error) - XCTAssertEqual(order, [1, 0, 0, 0]) - } - } - #endif - - internal func testCancel() { - let queue = Queuer(name: "SynchronousOperationTestCancel") - queue.maxConcurrentOperationCount = 1 - let testExpectation = expectation(description: "Cancel") - var testString = "" - - let deadline = DispatchTime.now() + .seconds(2) - DispatchQueue.global(qos: .background).asyncAfter(deadline: deadline) { - queue.cancelAll() - testExpectation.fulfill() - } - - let synchronousOperation1 = SynchronousOperation { _ in - testString = "Tested1" - Thread.sleep(forTimeInterval: 4) - } - let synchronousOperation2 = SynchronousOperation { _ in - testString = "Tested2" - } - synchronousOperation1.addToQueue(queue) - synchronousOperation2.addToQueue(queue) - - XCTAssertFalse(synchronousOperation1.isAsynchronous) - XCTAssertFalse(synchronousOperation2.isAsynchronous) - - waitForExpectations(timeout: 5) { error in - XCTAssertNil(error) - XCTAssertEqual(testString, "Tested1") - } - } -} diff --git a/generate_linux_tests.rb b/generate_linux_tests.rb deleted file mode 100644 index 6c93862..0000000 --- a/generate_linux_tests.rb +++ /dev/null @@ -1,248 +0,0 @@ -#!/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 -// -// MIT License -// -// Copyright (c) 2017 - 2019 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 ' 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 [\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 )\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 = false - ignore = true - 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 diff --git a/install_swiftlint.sh b/install_swiftlint.sh deleted file mode 100755 index 84e4f80..0000000 --- a/install_swiftlint.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Installs the SwiftLint package. -# Tries to get the precompiled .pkg file from Github, but if that -# fails just recompiles from source. - -set -e - -SWIFTLINT_PKG_PATH="/tmp/SwiftLint.pkg" -SWIFTLINT_PKG_URL="https://github.com/realm/SwiftLint/releases/download/0.35.0/SwiftLint.pkg" - -wget --output-document=$SWIFTLINT_PKG_PATH $SWIFTLINT_PKG_URL - -if [ -f $SWIFTLINT_PKG_PATH ]; then - echo "SwiftLint package exists! Installing it..." - sudo installer -pkg $SWIFTLINT_PKG_PATH -target / -else - echo "SwiftLint package doesn't exist. Compiling from source..." && - git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint && - cd /tmp/SwiftLint && - git submodule update --init --recursive && - sudo make install -fi diff --git a/jazzy.sh b/jazzy.sh deleted file mode 100755 index d57a2a0..0000000 --- a/jazzy.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Creates documentation using Jazzy. - -FRAMEWORK_VERSION=2.1.1 - -jazzy \ - --clean \ - --author "Fabrizio Brancati" \ - --author_url https://www.fabriziobrancati.com \ - --github_url https://github.com/FabrizioBrancati/Queuer \ - --github-file-prefix https://github.com/FabrizioBrancati/Queuer/tree/$FRAMEWORK_VERSION \ - --module-version $FRAMEWORK_VERSION \ - --xcodebuild-arguments -scheme,"Queuer iOS" \ - --module Queuer \ - --root-url https://github.com/FabrizioBrancati/Queuer \ - --output Docs/ \ - --theme jony \ - --docset-icon Resources/Icon-32.png \ - --root-url https://github.fabriziobrancati.com/documentation/Queuer/ \ - --dash_url https://github.fabriziobrancati.com/documentation/Queuer/docsets/Queuer.xml - -cp -r Resources Docs/Resources