├── Configurations ├── Shared ├── Version.xcconfig ├── BoltsSwift-iOS.xcconfig ├── BoltsSwift-tvOS.xcconfig ├── BoltsSwift-macOS.xcconfig ├── BoltsSwift-watchOS.xcconfig ├── BoltsSwiftTests-iOS.xcconfig ├── BoltsSwiftTests-tvOS.xcconfig ├── BoltsSwiftTests-macOS.xcconfig ├── BoltsSwiftTests-Shared.xcconfig └── BoltsSwift-Shared.xcconfig ├── .gitmodules ├── .github_changelog_generator ├── .codecov.yml ├── .swiftlint.yml ├── BoltsSwift.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── BoltsSwift.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ ├── BoltsSwift-watchOS.xcscheme │ │ ├── BoltsSwift-iOS.xcscheme │ │ ├── BoltsSwift-tvOS.xcscheme │ │ └── BoltsSwift-macOS.xcscheme └── project.pbxproj ├── CODE_OF_CONDUCT.md ├── .gitignore ├── Tests ├── XCTestCase+TestName.swift ├── Info.plist ├── TaskCompletionSourceTests.swift ├── ExecutorTests.swift └── TaskTests.swift ├── Package.swift ├── Bolts-Swift.podspec ├── Sources ├── Info.plist └── BoltsSwift │ ├── Errors.swift │ ├── Task+Delay.swift │ ├── Task+WhenAny.swift │ ├── TaskCompletionSource.swift │ ├── Task+WhenAll.swift │ ├── Executor.swift │ ├── Task+ContinueWith.swift │ └── Task.swift ├── CONTRIBUTING.md ├── LICENSE ├── PATENTS ├── .travis.yml ├── CHANGELOG.md └── README.md /Configurations/Shared: -------------------------------------------------------------------------------- 1 | ../Vendor/xctoolchain/Configurations/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Vendor/xctoolchain"] 2 | path = Vendor/xctoolchain 3 | url = https://github.com/nlutsenko/xctoolchain.git 4 | -------------------------------------------------------------------------------- /.github_changelog_generator: -------------------------------------------------------------------------------- 1 | issues=true 2 | issues-wo-labels=false 3 | exclude_labels=duplicate,question,wontfix,discussion,needs more info,backend,cocoapods,off topic,product usage,invalid 4 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - Tests/.* 4 | status: 5 | patch: false 6 | changes: false 7 | project: 8 | default: 9 | target: 75 10 | comment: false 11 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 140 2 | file_length: 1000 3 | type_body_length: 500 4 | opt_in_rules: 5 | - empty_count 6 | disabled_rules: 7 | - cyclomatic_complexity 8 | - variable_name 9 | - no_fallthrough_only 10 | -------------------------------------------------------------------------------- /BoltsSwift.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BoltsSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated. -------------------------------------------------------------------------------- /BoltsSwift.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Configurations/Version.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | BOLTS_SWIFT_VERSION = 1.5.0 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## OS X 2 | .DS_Store 3 | 4 | ## Build generated 5 | .build/ 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Dependency Managers 31 | Pods/ 32 | Carthage/Build 33 | 34 | ## AppCode 35 | .idea/ 36 | -------------------------------------------------------------------------------- /Configurations/BoltsSwift-iOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/iOS.xcconfig" 11 | 12 | #include "BoltsSwift-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.ios 15 | 16 | IPHONEOS_DEPLOYMENT_TARGET = 11.0 17 | -------------------------------------------------------------------------------- /Configurations/BoltsSwift-tvOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/tvOS.xcconfig" 11 | 12 | #include "BoltsSwift-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.tvos 15 | 16 | TVOS_DEPLOYMENT_TARGET = 11.0 17 | -------------------------------------------------------------------------------- /Configurations/BoltsSwift-macOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/macOS.xcconfig" 11 | 12 | #include "BoltsSwift-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.macos 15 | 16 | MACOSX_DEPLOYMENT_TARGET = 10.13 17 | -------------------------------------------------------------------------------- /Configurations/BoltsSwift-watchOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/watchOS.xcconfig" 11 | 12 | #include "BoltsSwift-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.watchos 15 | 16 | WATCHOS_DEPLOYMENT_TARGET = 4.0 17 | -------------------------------------------------------------------------------- /Configurations/BoltsSwiftTests-iOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/iOS.xcconfig" 11 | 12 | #include "BoltsSwiftTests-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.ios.tests 15 | 16 | IPHONEOS_DEPLOYMENT_TARGET = 11.0 17 | -------------------------------------------------------------------------------- /Configurations/BoltsSwiftTests-tvOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/tvOS.xcconfig" 11 | 12 | #include "BoltsSwiftTests-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.tvos.tests 15 | 16 | TVOS_DEPLOYMENT_TARGET = 11.0 17 | -------------------------------------------------------------------------------- /Configurations/BoltsSwiftTests-macOS.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Platform/macOS.xcconfig" 11 | 12 | #include "BoltsSwiftTests-Shared.xcconfig" 13 | 14 | PRODUCT_BUNDLE_IDENTIFIER = com.bolts.swift.macos.tests 15 | 16 | MACOSX_DEPLOYMENT_TARGET = 10.13 17 | -------------------------------------------------------------------------------- /Tests/XCTestCase+TestName.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import XCTest 11 | 12 | extension XCTestCase { 13 | /** 14 | Waits for all test expectations with a default timeout. 15 | */ 16 | func waitForTestExpectations() { 17 | waitForExpectations(timeout: 10, handler: nil) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Configurations/BoltsSwiftTests-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Product/LogicTests.xcconfig" 11 | 12 | // 13 | // This file contains shared configuration for all "Tests" targets. 14 | // Only shared configurations belong here. 15 | // 16 | 17 | PRODUCT_NAME = BoltsSwiftTests 18 | 19 | SWIFT_VERSION = 5.0 20 | 21 | INFOPLIST_FILE = $(SRCROOT)/Tests/Info.plist 22 | -------------------------------------------------------------------------------- /Configurations/BoltsSwift-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | #include "Shared/Product/DynamicFramework.xcconfig" 11 | 12 | #include "Version.xcconfig" 13 | 14 | // 15 | // This file contains shared configuration for all "Framework" targets. 16 | // Only shared configurations belong here. 17 | // 18 | 19 | PRODUCT_NAME = BoltsSwift 20 | 21 | SWIFT_VERSION = 5.0 22 | 23 | INFOPLIST_FILE = $(SRCROOT)/Sources/Info.plist 24 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "BoltsSwift", 7 | platforms: [.macOS(.v10_10), 8 | .iOS(.v8), 9 | .tvOS(.v9), 10 | .watchOS(.v3)], 11 | products: [ 12 | .library( 13 | name: "BoltsSwift", 14 | targets: ["BoltsSwift"]) 15 | ], 16 | targets: [ 17 | .target( 18 | name: "BoltsSwift", 19 | path: "Sources/BoltsSwift"), 20 | .testTarget( 21 | name: "BoltsSwiftTests", 22 | dependencies: ["BoltsSwift"], 23 | path: "Tests") 24 | ], 25 | swiftLanguageVersions: [.v4, 26 | .v4_2, 27 | .v5] 28 | ) 29 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Bolts-Swift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Bolts-Swift' 3 | s.version = '1.5.0' 4 | s.license = { :type => 'BSD' } 5 | s.summary = 'Bolts is a collection of low-level libraries designed to make developing mobile apps easier.' 6 | s.homepage = 'https://github.com/BoltsFramework' 7 | s.authors = { 'Nikita Lutsenko' => 'nlutsenko@me.com' } 8 | 9 | s.source = { :git => 'https://github.com/BoltsFramework/Bolts-Swift.git', :tag => s.version.to_s } 10 | 11 | s.requires_arc = true 12 | 13 | s.swift_version = '5.0' 14 | 15 | s.ios.deployment_target = '8.0' 16 | s.osx.deployment_target = '10.10' 17 | s.tvos.deployment_target = '9.0' 18 | s.watchos.deployment_target = '2.0' 19 | 20 | s.source_files = 'Sources/BoltsSwift/*.swift' 21 | s.module_name = 'BoltsSwift' 22 | end 23 | -------------------------------------------------------------------------------- /Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(BOLTS_SWIFT_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(BOLTS_SWIFT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/Errors.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | /** 13 | An error type that contains one or more underlying errors. 14 | */ 15 | public struct AggregateError: Error { 16 | /// An array of errors that are aggregated into this one. 17 | public let errors: [Error] 18 | 19 | init(errors: [Error]) { 20 | self.errors = errors 21 | } 22 | } 23 | 24 | /** 25 | An error type that indicates that the task was cancelled. 26 | 27 | Return or throw this from a continuation closure to propagate to the `task.cancelled` property. 28 | */ 29 | public struct CancelledError: Error { 30 | /** 31 | Initializes a Cancelled Error. 32 | */ 33 | public init() { } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/Task+Delay.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | //-------------------------------------- 13 | // MARK: - Task with Delay 14 | //-------------------------------------- 15 | 16 | extension Task { 17 | /** 18 | Creates a task that will complete after the given delay. 19 | 20 | - parameter delay: The delay for the task to completes. 21 | 22 | - returns: A task that will complete after the given delay. 23 | */ 24 | public class func withDelay(_ delay: TimeInterval) -> Task { 25 | let taskCompletionSource = TaskCompletionSource() 26 | let time = DispatchTime.now() + delay 27 | DispatchQueue.global(qos: .default).asyncAfter(deadline: time) { 28 | taskCompletionSource.trySet(result: ()) 29 | } 30 | return taskCompletionSource.task 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Bolts-Swift 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Pull Requests 6 | We actively welcome your pull requests. 7 | 8 | 1. Fork the repo and create your branch from `master`. 9 | 2. If you've added code that should be tested, add tests. 10 | 3. If you've changed APIs, update the documentation. 11 | 4. Ensure the test suite passes. 12 | 5. Make sure your code lints. 13 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 14 | 15 | ## Contributor License Agreement ("CLA") 16 | In order to accept your pull request, we need you to submit a CLA. You only need 17 | to do this once to work on any of Facebook's open source projects. 18 | 19 | Complete your CLA here: 20 | 21 | ## Issues 22 | We use GitHub issues to track public bugs. Please ensure your description is 23 | clear and has sufficient instructions to be able to reproduce the issue. 24 | 25 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe 26 | disclosure of security bugs. In those cases, please go through the process 27 | outlined on that page and do not file a public issue. 28 | 29 | ## Coding Style 30 | * Most importantly, match the existing code style as much as possible. 31 | * Try to keep lines under 140 characters, if possible. 32 | 33 | ## License 34 | By contributing to Bolts-Swift, you agree that your contributions will be licensed 35 | under its BSD license. 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For Bolts-Swift software 4 | 5 | Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the Bolts-Swift software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. -------------------------------------------------------------------------------- /Sources/BoltsSwift/Task+WhenAny.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | //-------------------------------------- 13 | // MARK: - WhenAny 14 | //-------------------------------------- 15 | 16 | extension Task { 17 | 18 | /** 19 | Creates a task that will complete when any of the input tasks have completed. 20 | 21 | The returned task will complete when any of the supplied tasks have completed. 22 | This is true even if the first task to complete ended in the canceled or faulted state. 23 | 24 | - parameter tasks: Array of tasks to wait on for completion. 25 | 26 | - returns: A new task that will complete when any of the `tasks` are completed. 27 | */ 28 | public class func whenAny(_ tasks: [Task]) -> Task { 29 | if tasks.isEmpty { 30 | return Task.emptyTask() 31 | } 32 | let taskCompletionSource = TaskCompletionSource() 33 | for task in tasks { 34 | // Do not continue anything if we completed the task, because we fulfilled our job here. 35 | if taskCompletionSource.task.completed { 36 | break 37 | } 38 | task.continueWith { _ in 39 | taskCompletionSource.trySet(result: ()) 40 | } 41 | } 42 | return taskCompletionSource.task 43 | } 44 | 45 | /** 46 | Creates a task that will complete when any of the input tasks have completed. 47 | 48 | The returned task will complete when any of the supplied tasks have completed. 49 | This is true even if the first task to complete ended in the canceled or faulted state. 50 | 51 | - parameter tasks: Zeror or more tasks to wait on for completion. 52 | 53 | - returns: A new task that will complete when any of the `tasks` are completed. 54 | */ 55 | public class func whenAny(_ tasks: Task...) -> Task { 56 | return whenAny(tasks) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /BoltsSwift.xcodeproj/xcshareddata/xcschemes/BoltsSwift-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | language: objective-c 5 | os: osx 6 | cache: 7 | - cocoapods 8 | matrix: 9 | include: 10 | - osx_image: xcode9 11 | env: TEST_TYPE=iOS SWIFT_VERSION=4.0 DESTINATION='platform=iOS Simulator,name=iPhone 4s,OS=8.1' 12 | - osx_image: xcode10 13 | env: TEST_TYPE=iOS SWIFT_VERSION=4.2 DESTINATION='platform=iOS Simulator,name=iPhone X,OS=11.1' 14 | - osx_image: xcode11 15 | env: TEST_TYPE=iOS SWIFT_VERSION=5.0 DESTINATION='platform=iOS Simulator,name=iPhone 11 Pro,OS=13.0' 16 | - osx_image: xcode11 17 | env: TEST_TYPE=macOS SWIFT_VERSION=5.0 18 | - osx_image: xcode11 19 | env: TEST_TYPE=tvOS SWIFT_VERSION=5.0 20 | - osx_image: xcode11 21 | env: TEST_TYPE=SwiftPM 22 | - osx_image: xcode11 23 | env: TEST_TYPE=Lint 24 | - osx_image: xcode11 25 | env: TEST_TYPE=Distribution 26 | before_install: 27 | - | 28 | if [ "$TEST_TYPE" = Lint ] || [ "$TEST_TYPE" = Distribution ]; then 29 | brew update 30 | fi 31 | install: 32 | - | 33 | if [ "$TEST_TYPE" = iOS ] || [ "$TEST_TYPE" = macOS ] || [ "$TEST_TYPE" = tvOS ]; then 34 | gem install xcpretty --no-document 35 | elif [ "$TEST_TYPE" = Lint ]; then 36 | brew install swiftlint || brew upgrade swiftlint 37 | elif [ "$TEST_TYPE" = Distribution ]; then 38 | gem install cocoapods --pre --quiet --no-document 39 | brew install carthage || brew upgrade carthage 40 | fi 41 | script: 42 | - | 43 | [ ! -z "$SWIFT_VERSION" ] && sed -i '' -e "s/^SWIFT_VERSION *=.*/SWIFT_VERSION = $SWIFT_VERSION/g" Configurations/*.xcconfig 44 | if [ "$TEST_TYPE" = iOS ]; then 45 | set -o pipefail 46 | xcodebuild test -project BoltsSwift.xcodeproj -sdk iphonesimulator -scheme BoltsSwift-iOS -configuration Debug -destination "$DESTINATION" GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 47 | xcodebuild test -project BoltsSwift.xcodeproj -sdk iphonesimulator -scheme BoltsSwift-iOS -configuration Release -destination "$DESTINATION" GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 48 | elif [ "$TEST_TYPE" = macOS ]; then 49 | set -o pipefail 50 | xcodebuild test -project BoltsSwift.xcodeproj -sdk macosx -scheme BoltsSwift-macOS -configuration Debug GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 51 | xcodebuild test -project BoltsSwift.xcodeproj -sdk macosx -scheme BoltsSwift-macOS -configuration Release GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 52 | elif [ "$TEST_TYPE" = tvOS ]; then 53 | set -o pipefail 54 | xcodebuild test -project BoltsSwift.xcodeproj -sdk appletvsimulator -scheme BoltsSwift-tvOS -destination "platform=tvOS Simulator,name=Apple TV" -configuration Debug GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 55 | xcodebuild test -project BoltsSwift.xcodeproj -sdk appletvsimulator -scheme BoltsSwift-tvOS -destination "platform=tvOS Simulator,name=Apple TV" -configuration Release GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 56 | elif [ "$TEST_TYPE" = SwiftPM ]; then 57 | swift test -v 58 | elif [ "$TEST_TYPE" = Lint ]; then 59 | swiftlint lint 60 | elif [ "$TEST_TYPE" = Distribution ]; then 61 | pod lib lint Bolts-Swift.podspec 62 | carthage build --no-skip-current 63 | fi 64 | after_success: 65 | - | 66 | if [ "$TEST_TYPE" = iOS ] || [ "$TEST_TYPE" = macOS ] || [ "$TEST_TYPE" = tvOS ]; then 67 | bash <(curl -s https://codecov.io/bash) 68 | fi 69 | -------------------------------------------------------------------------------- /Tests/TaskCompletionSourceTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import XCTest 11 | import BoltsSwift 12 | 13 | class TaskCompletionSourceTests: XCTestCase { 14 | 15 | func testInit() { 16 | let tcs = TaskCompletionSource() 17 | let task = tcs.task 18 | 19 | XCTAssertFalse(task.completed) 20 | XCTAssertFalse(task.faulted) 21 | XCTAssertFalse(task.cancelled) 22 | XCTAssertNil(task.result) 23 | XCTAssertNil(task.error) 24 | } 25 | 26 | func testSetResult() { 27 | let tcs = TaskCompletionSource() 28 | let task = tcs.task 29 | 30 | tcs.set(result: name) 31 | 32 | XCTAssertTrue(task.completed) 33 | XCTAssertNotNil(task.result) 34 | XCTAssertEqual(task.result, name) 35 | } 36 | 37 | func testSetError() { 38 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 39 | let tcs = TaskCompletionSource() 40 | let task = tcs.task 41 | 42 | tcs.set(error: error) 43 | 44 | XCTAssertTrue(task.completed) 45 | XCTAssertTrue(task.faulted) 46 | XCTAssertNotNil(task.error) 47 | XCTAssertEqual(task.error as NSError?, error) 48 | } 49 | 50 | func testCancel() { 51 | let tcs = TaskCompletionSource() 52 | let task = tcs.task 53 | 54 | tcs.cancel() 55 | 56 | XCTAssertTrue(task.completed) 57 | XCTAssertTrue(task.cancelled) 58 | } 59 | 60 | func testTrySetResultReturningTrue() { 61 | let sut = TaskCompletionSource() 62 | let task = sut.task 63 | 64 | let success = sut.trySet(result: name) 65 | 66 | XCTAssertTrue(success) 67 | XCTAssertTrue(task.completed) 68 | XCTAssertNotNil(task.result) 69 | XCTAssertEqual(task.result, name) 70 | } 71 | 72 | func testTrySetErrorReturningTrue() { 73 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 74 | let sut = TaskCompletionSource() 75 | let task = sut.task 76 | 77 | let success = sut.trySet(error: error) 78 | 79 | XCTAssertTrue(success) 80 | XCTAssertTrue(task.completed) 81 | XCTAssertTrue(task.faulted) 82 | XCTAssertNotNil(task.error) 83 | XCTAssertEqual(task.error as NSError?, error) 84 | } 85 | 86 | func testTryCancelReturningTrue() { 87 | let sut = TaskCompletionSource() 88 | let task = sut.task 89 | 90 | let success = sut.tryCancel() 91 | 92 | XCTAssertTrue(success) 93 | XCTAssertTrue(task.completed) 94 | XCTAssertTrue(task.cancelled) 95 | } 96 | 97 | func testTrySetResultReturningFalse() { 98 | let sut = TaskCompletionSource() 99 | sut.set(result: name) 100 | 101 | let success = sut.trySet(result: name) 102 | 103 | XCTAssertFalse(success) 104 | } 105 | 106 | func testTrySetErrorReturningFalse() { 107 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 108 | let sut = TaskCompletionSource() 109 | sut.set(result: name) 110 | 111 | let success = sut.trySet(error: error) 112 | 113 | XCTAssertFalse(success) 114 | } 115 | 116 | func testTryCancelReturningFalse() { 117 | let sut = TaskCompletionSource() 118 | sut.set(result: name) 119 | let success = sut.tryCancel() 120 | XCTAssertFalse(success) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /BoltsSwift.xcodeproj/xcshareddata/xcschemes/BoltsSwift-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /BoltsSwift.xcodeproj/xcshareddata/xcschemes/BoltsSwift-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/TaskCompletionSource.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | /// A `TaskCompletionSource` represents the producer side of a `Task`, 13 | /// providing access to the consumer side through the `task` property. 14 | /// As a producer, it can complete the underlying task by either by setting its result, error or cancelling it. 15 | /// 16 | /// For example, this is how you could use a task completion source 17 | /// to provide a task that asynchronously reads data from disk: 18 | /// 19 | /// func dataFromPath(path: String) -> Task { 20 | /// let tcs = TaskCompletionSource() 21 | /// DispatchQueue.global(qos: .default).async { 22 | /// if let data = NSData(contentsOfFile: path) { 23 | /// tcs.set(result: data) 24 | /// } else { 25 | /// tcs.set(error: NSError(domain: "com.example", code: 0, userInfo: nil)) 26 | /// } 27 | /// } 28 | /// return tcs.task 29 | /// } 30 | public class TaskCompletionSource { 31 | 32 | /// The underlying task. 33 | public let task = Task() 34 | 35 | /// Creates a task completion source with a pending task. 36 | public init() {} 37 | 38 | //-------------------------------------- 39 | // MARK: - Change Task State 40 | //-------------------------------------- 41 | 42 | /** 43 | Completes the task with the given result. 44 | 45 | Throws an exception if the task is already completed. 46 | 47 | - parameter result: The task result. 48 | */ 49 | public func set(result: TResult) { 50 | guard task.trySet(state: .success(result)) else { 51 | preconditionFailure("Can not set the result on a completed task.") 52 | } 53 | } 54 | 55 | /** 56 | Completes the task with the given error. 57 | 58 | Throws an exception if the task is already completed. 59 | 60 | - parameter error: The task error. 61 | */ 62 | public func set(error: Error) { 63 | guard task.trySet(state: .error(error)) else { 64 | preconditionFailure("Can not set error on a completed task.") 65 | } 66 | } 67 | 68 | /** 69 | Cancels the task. 70 | 71 | Throws an exception if the task is already completed. 72 | */ 73 | public func cancel() { 74 | guard task.trySet(state: .cancelled) else { 75 | preconditionFailure("Can not cancel a completed task.") 76 | } 77 | } 78 | 79 | /** 80 | Tries to complete the task with the given result. 81 | 82 | - parameter result: The task result. 83 | - returns: `true` if the result was set, `false` otherwise. 84 | */ 85 | @discardableResult 86 | public func trySet(result: TResult) -> Bool { 87 | return task.trySet(state: .success(result)) 88 | } 89 | 90 | /** 91 | Tries to completes the task with the given error. 92 | 93 | - parameter error: The task error. 94 | - returns: `true` if the error was set, `false` otherwise. 95 | */ 96 | @discardableResult 97 | public func trySet(error: Error) -> Bool { 98 | return task.trySet(state: .error(error)) 99 | } 100 | 101 | /** 102 | Cancels the task. 103 | 104 | - returns: `true` if the task was completed, `false` otherwise. 105 | */ 106 | @discardableResult 107 | public func tryCancel() -> Bool { 108 | return task.trySet(state: .cancelled) 109 | } 110 | 111 | //-------------------------------------- 112 | // MARK: - Change Task State (internal) 113 | //-------------------------------------- 114 | 115 | func setState(_ state: TaskState) { 116 | guard task.trySet(state: state) else { 117 | preconditionFailure("Can not complete a completed task.") 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/Task+WhenAll.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | //-------------------------------------- 13 | // MARK: - WhenAll 14 | //-------------------------------------- 15 | 16 | extension Task { 17 | 18 | /** 19 | Creates a task that will be completed after all of the input tasks have completed. 20 | 21 | - parameter tasks: Array tasks to wait on for completion. 22 | 23 | - returns: A new task that will complete after all `tasks` are completed. 24 | */ 25 | public class func whenAll(_ tasks: [Task]) -> Task { 26 | if tasks.isEmpty { 27 | return Task.emptyTask() 28 | } 29 | 30 | var tasksCount: Int32 = Int32(tasks.count) 31 | var cancelledCount: Int32 = 0 32 | var errorCount: Int32 = 0 33 | 34 | let tcs = TaskCompletionSource() 35 | tasks.forEach { 36 | $0.continueWith { task -> Void in 37 | if task.cancelled { 38 | OSAtomicIncrement32(&cancelledCount) 39 | } else if task.faulted { 40 | OSAtomicIncrement32(&errorCount) 41 | } 42 | 43 | if OSAtomicDecrement32(&tasksCount) == 0 { 44 | if cancelledCount > 0 { 45 | tcs.cancel() 46 | } else if errorCount > 0 { 47 | #if swift(>=4.1) 48 | tcs.set(error: AggregateError(errors: tasks.compactMap({ $0.error }))) 49 | #else 50 | tcs.set(error: AggregateError(errors: tasks.flatMap({ $0.error }))) 51 | #endif 52 | } else { 53 | tcs.set(result: ()) 54 | } 55 | } 56 | } 57 | } 58 | return tcs.task 59 | } 60 | 61 | /** 62 | Creates a task that will be completed after all of the input tasks have completed. 63 | 64 | - parameter tasks: Zero or more tasks to wait on for completion. 65 | 66 | - returns: A new task that will complete after all `tasks` are completed. 67 | */ 68 | public class func whenAll(_ tasks: Task...) -> Task { 69 | return whenAll(tasks) 70 | } 71 | 72 | /** 73 | Creates a task that will be completed after all of the input tasks have completed. 74 | 75 | - parameter tasks: Array of tasks to wait on for completion. 76 | 77 | - returns: A new task that will complete after all `tasks` are completed. 78 | The result of the task is going an array of results of all tasks in the same order as they were provided. 79 | */ 80 | public class func whenAllResult(_ tasks: [Task]) -> Task<[TResult]> { 81 | return whenAll(tasks).continueOnSuccessWithTask { task -> Task<[TResult]> in 82 | let results: [TResult] = tasks.map { task in 83 | guard let result = task.result else { 84 | // This should never happen. 85 | // If the task succeeded - there is no way result is `nil`, even in case TResult is optional, 86 | // because `task.result` would have a type of `Result??`, and we unwrap only one optional here. 87 | // If a task was cancelled, we should have never have gotten past 'continueOnSuccess'. 88 | // If a task errored, we should have returned a 'AggregateError' and never gotten past 'continueOnSuccess'. 89 | // If a task was pending, then something went horribly wrong. 90 | fatalError("Task is in unknown state \(task.state).") 91 | } 92 | return result 93 | } 94 | return Task<[TResult]>(results) 95 | } 96 | } 97 | 98 | /** 99 | Creates a task that will be completed after all of the input tasks have completed. 100 | 101 | - parameter tasks: Zero or more tasks to wait on for completion. 102 | 103 | - returns: A new task that will complete after all `tasks` are completed. 104 | The result of the task is going an array of results of all tasks in the same order as they were provided. 105 | */ 106 | public class func whenAllResult(_ tasks: Task...) -> Task<[TResult]> { 107 | return whenAllResult(tasks) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /BoltsSwift.xcodeproj/xcshareddata/xcschemes/BoltsSwift-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 52 | 53 | 54 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 77 | 78 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Tests/ExecutorTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import XCTest 11 | import BoltsSwift 12 | 13 | class ExecutorTests: XCTestCase { 14 | 15 | func testDefaultExecute() { 16 | let expectation = self.expectation(description: name) 17 | 18 | var finished = false 19 | Executor.default.execute { 20 | expectation.fulfill() 21 | finished = true 22 | } 23 | 24 | XCTAssertTrue(finished) 25 | waitForTestExpectations() 26 | } 27 | 28 | func testImmediateExecute() { 29 | let expectation = self.expectation(description: name) 30 | 31 | var finished = false 32 | Executor.immediate.execute { 33 | expectation.fulfill() 34 | finished = true 35 | } 36 | 37 | XCTAssertTrue(finished) 38 | waitForTestExpectations() 39 | } 40 | 41 | func testMainThreadSyncExecute() { 42 | let expectation = self.expectation(description: name) 43 | 44 | var finished = false 45 | Executor.mainThread.execute { 46 | expectation.fulfill() 47 | finished = true 48 | } 49 | 50 | XCTAssertTrue(finished) 51 | waitForTestExpectations() 52 | } 53 | 54 | func testMainThreadAsyncExecute() { 55 | let expectation = self.expectation(description: name) 56 | 57 | var finished = false 58 | DispatchQueue.global(qos: .default).async { 59 | Executor.mainThread.execute { 60 | finished = true 61 | expectation.fulfill() 62 | } 63 | } 64 | waitForTestExpectations() 65 | XCTAssertTrue(finished) 66 | } 67 | 68 | func testQueueExecute() { 69 | let expectation = self.expectation(description: name) 70 | let semaphore = DispatchSemaphore(value: 0) 71 | var finished = false 72 | 73 | Executor.queue(.global(qos: .default)).execute { 74 | semaphore.wait() 75 | finished = true 76 | expectation.fulfill() 77 | } 78 | 79 | XCTAssertFalse(finished) 80 | semaphore.signal() 81 | waitForTestExpectations() 82 | XCTAssertTrue(finished) 83 | } 84 | 85 | func testClosureExecute() { 86 | let expectation = self.expectation(description: name) 87 | 88 | Executor.closure { closure in 89 | closure() 90 | }.execute { () -> Void in 91 | expectation.fulfill() 92 | } 93 | 94 | waitForTestExpectations() 95 | } 96 | 97 | func testEscapingClosureExecute() { 98 | let expectation = self.expectation(description: name) 99 | Executor.escapingClosure { closure in 100 | closure() 101 | }.execute { () -> Void in 102 | expectation.fulfill() 103 | } 104 | 105 | waitForTestExpectations() 106 | } 107 | 108 | func testOperationQueueExecute() { 109 | let expectation = self.expectation(description: name) 110 | let semaphore = DispatchSemaphore(value: 0) 111 | var finished = false 112 | 113 | let operationQueue = OperationQueue() 114 | Executor.operationQueue(operationQueue).execute { 115 | semaphore.wait() 116 | finished = true 117 | expectation.fulfill() 118 | } 119 | 120 | XCTAssertFalse(finished) 121 | semaphore.signal() 122 | waitForTestExpectations() 123 | XCTAssertTrue(finished) 124 | } 125 | 126 | // MARK: Descriptions 127 | 128 | func testDescriptions() { 129 | XCTAssertFalse(Executor.default.description.isEmpty) 130 | XCTAssertFalse(Executor.immediate.description.isEmpty) 131 | XCTAssertFalse(Executor.mainThread.description.isEmpty) 132 | XCTAssertFalse(Executor.queue(.global(qos: .default)).description.isEmpty) 133 | XCTAssertFalse(Executor.operationQueue(OperationQueue.current!).description.isEmpty) 134 | XCTAssertFalse(Executor.closure({ _ in }).description.isEmpty) 135 | } 136 | 137 | func testDebugDescriptions() { 138 | XCTAssertFalse(Executor.default.debugDescription.isEmpty) 139 | XCTAssertFalse(Executor.immediate.debugDescription.isEmpty) 140 | XCTAssertFalse(Executor.mainThread.debugDescription.isEmpty) 141 | XCTAssertFalse(Executor.queue(.global(qos: .default)).debugDescription.isEmpty) 142 | XCTAssertFalse(Executor.operationQueue(OperationQueue.current!).debugDescription.isEmpty) 143 | XCTAssertFalse(Executor.closure({ _ in }).debugDescription.isEmpty) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/Executor.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | /// `Executor` is an `enum`, that defines different strategies for calling closures. 13 | public enum Executor { 14 | 15 | /** 16 | Calls closures immediately unless the call stack gets too deep, 17 | in which case it dispatches the closure in the default priority queue. 18 | */ 19 | case `default` 20 | 21 | /** 22 | Calls closures immediately. 23 | Tasks continuations will be run in the thread of the previous task. 24 | */ 25 | case immediate 26 | 27 | /** 28 | Calls closures on the main thread. 29 | Will execute synchronously if already on the main thread, otherwise - will execute asynchronously. 30 | */ 31 | case mainThread 32 | 33 | /** 34 | Dispatches closures on a GCD queue. 35 | */ 36 | case queue(DispatchQueue) 37 | 38 | /** 39 | Adds closures to an operation queue. 40 | */ 41 | case operationQueue(Foundation.OperationQueue) 42 | 43 | /** 44 | Passes closures to an executing closure. 45 | */ 46 | case closure((() -> Void) -> Void) 47 | 48 | /** 49 | Passes escaping closures to an executing closure. 50 | */ 51 | case escapingClosure((@escaping () -> Void) -> Void) 52 | 53 | /** 54 | Executes the given closure using the corresponding strategy. 55 | 56 | - parameter closure: The closure to execute. 57 | */ 58 | public func execute(_ closure: @escaping () -> Void) { 59 | switch self { 60 | case .default: 61 | struct Static { 62 | static let taskDepthKey = "com.bolts.TaskDepthKey" 63 | static let maxTaskDepth = 20 64 | } 65 | 66 | let localThreadDictionary = Thread.current.threadDictionary 67 | 68 | var previousDepth: Int 69 | if let depth = localThreadDictionary[Static.taskDepthKey] as? Int { 70 | previousDepth = depth 71 | } else { 72 | previousDepth = 0 73 | } 74 | 75 | if previousDepth > Static.maxTaskDepth { 76 | DispatchQueue.global(qos: .default).async(execute: closure) 77 | } else { 78 | localThreadDictionary[Static.taskDepthKey] = previousDepth + 1 79 | closure() 80 | localThreadDictionary[Static.taskDepthKey] = previousDepth 81 | } 82 | case .immediate: 83 | closure() 84 | case .mainThread: 85 | if Thread.isMainThread { 86 | closure() 87 | } else { 88 | DispatchQueue.main.async(execute: closure) 89 | } 90 | case .queue(let queue): 91 | queue.async(execute: closure) 92 | case .operationQueue(let operationQueue): 93 | operationQueue.addOperation(closure) 94 | case .closure(let executingClosure): 95 | executingClosure(closure) 96 | case .escapingClosure(let executingEscapingClosure): 97 | executingEscapingClosure(closure) 98 | } 99 | } 100 | } 101 | 102 | extension Executor: CustomStringConvertible, CustomDebugStringConvertible { 103 | /// A textual representation of `self`. 104 | public var description: String { 105 | switch self { 106 | case .default: 107 | return "Default Executor" 108 | case .immediate: 109 | return "Immediate Executor" 110 | case .mainThread: 111 | return "MainThread Executor" 112 | case .queue: 113 | return "Executor with dispatch_queue" 114 | case .operationQueue: 115 | return "Executor with NSOperationQueue" 116 | case .closure: 117 | return "Executor with custom closure" 118 | case .escapingClosure: 119 | return "Executor with custom escaping closure" 120 | } 121 | } 122 | 123 | /// A textual representation of `self`, suitable for debugging. 124 | public var debugDescription: String { 125 | switch self { 126 | case .queue(let object): 127 | return "\(description): \(object)" 128 | case .operationQueue(let queue): 129 | return "\(description): \(queue)" 130 | case .closure(let closure): 131 | return "\(description): \(String(describing: closure))" 132 | case .escapingClosure(let closure): 133 | return "\(description): \(String(describing: closure))" 134 | default: 135 | return description 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [1.5.0](https://github.com/BoltsFramework/Bolts-Swift/tree/1.5.0) (2019-09-27) 4 | [Full Changelog](https://github.com/BoltsFramework/Bolts-Swift/compare/1.4.0...1.5.0) 5 | 6 | **Implemented enhancements:** 7 | 8 | - Add support for Swift Package Manager. [\#92](https://github.com/BoltsFramework/Bolts-Swift/pull/92) ([nlutsenko](https://github.com/nlutsenko)) 9 | - Update to Swift 5 and Xcode 11. [\#91](https://github.com/BoltsFramework/Bolts-Swift/pull/91) ([nlutsenko](https://github.com/nlutsenko)) 10 | 11 | **Merged pull requests:** 12 | 13 | - \[TravisCI\] fix it, test with Swift 4.0 and 4.2 \(5.0 prepared\) [\#87](https://github.com/BoltsFramework/Bolts-Swift/pull/87) ([HeEAaD](https://github.com/HeEAaD)) 14 | - Tweak README for readability & clarity [\#83](https://github.com/BoltsFramework/Bolts-Swift/pull/83) ([ermik](https://github.com/ermik)) 15 | - Adding Code of Conduct file [\#79](https://github.com/BoltsFramework/Bolts-Swift/pull/79) ([facebook-github-bot](https://github.com/facebook-github-bot)) 16 | - Add swift\_version to podspec [\#75](https://github.com/BoltsFramework/Bolts-Swift/pull/75) ([hcanzonetta](https://github.com/hcanzonetta)) 17 | 18 | ## [1.4.0](https://github.com/BoltsFramework/Bolts-Swift/tree/1.4.0) (2018-07-19) 19 | [Full Changelog](https://github.com/BoltsFramework/Bolts-Swift/compare/1.3.0...1.4.0) 20 | 21 | **Implemented enhancements:** 22 | 23 | - Remove flatMap because it is now deprecated in Swift 4.1 [\#71](https://github.com/BoltsFramework/Bolts-Swift/pull/71) ([sebleclerc](https://github.com/sebleclerc)) 24 | - Swift 4.0 Support [\#64](https://github.com/BoltsFramework/Bolts-Swift/pull/64) ([nlutsenko](https://github.com/nlutsenko)) 25 | - Adding a new executor which takes an escaping closure [\#58](https://github.com/BoltsFramework/Bolts-Swift/pull/58) ([sebleclerc](https://github.com/sebleclerc)) 26 | 27 | **Merged pull requests:** 28 | 29 | - Changed casing of Executor enum value in README. [\#56](https://github.com/BoltsFramework/Bolts-Swift/pull/56) ([sjorsvb](https://github.com/sjorsvb)) 30 | - Bolts 1.4.0 🔩 [\#74](https://github.com/BoltsFramework/Bolts-Swift/pull/74) ([nlutsenko](https://github.com/nlutsenko)) 31 | 32 | ## [1.3.0](https://github.com/BoltsFramework/Bolts-Swift/tree/1.3.0) (2016-09-20) 33 | [Full Changelog](https://github.com/BoltsFramework/Bolts-Swift/compare/1.2.0...1.3.0) 34 | 35 | **Implemented enhancements:** 36 | 37 | - Add Swift 3.0 support. [\#40](https://github.com/BoltsFramework/Bolts-Swift/pull/40) ([nlutsenko](https://github.com/nlutsenko)) 38 | 39 | **Closed issues:** 40 | 41 | - Swift 3.0 Support [\#33](https://github.com/BoltsFramework/Bolts-Swift/issues/33) 42 | 43 | **Merged pull requests:** 44 | 45 | - Update a TaskCompletionSource usage example for Swift 3.0. [\#48](https://github.com/BoltsFramework/Bolts-Swift/pull/48) ([sapzildj](https://github.com/sapzildj)) 46 | - Bolts 1.3.0 🔩 [\#42](https://github.com/BoltsFramework/Bolts-Swift/pull/42) ([nlutsenko](https://github.com/nlutsenko)) 47 | - Set lowest deployment macOS target to 10.10. [\#41](https://github.com/BoltsFramework/Bolts-Swift/pull/41) ([nlutsenko](https://github.com/nlutsenko)) 48 | - Fix README for TaskCompletionSource.cancel\(\) [\#37](https://github.com/BoltsFramework/Bolts-Swift/pull/37) ([ceyhun](https://github.com/ceyhun)) 49 | 50 | ## [1.2.0](https://github.com/BoltsFramework/Bolts-Swift/tree/1.2.0) (2016-07-25) 51 | [Full Changelog](https://github.com/BoltsFramework/Bolts-Swift/compare/1.1.0...1.2.0) 52 | 53 | **Implemented enhancements:** 54 | 55 | - Implement new set of continuations for error-only use case. [\#17](https://github.com/BoltsFramework/Bolts-Swift/issues/17) 56 | - Make all 'trySet', 'set' functions to use explicit argument labels. [\#30](https://github.com/BoltsFramework/Bolts-Swift/pull/30) ([nlutsenko](https://github.com/nlutsenko)) 57 | - Update project/tests for Xcode 8 and Swift 2.3. [\#27](https://github.com/BoltsFramework/Bolts-Swift/pull/27) ([nlutsenko](https://github.com/nlutsenko)) 58 | - Make CompletedCondtion optional, should improve memory usage slightly. [\#25](https://github.com/BoltsFramework/Bolts-Swift/pull/25) ([richardjrossiii](https://github.com/richardjrossiii)) 59 | - Add continueOnErrorWith, continueOnErrorWithTask. [\#18](https://github.com/BoltsFramework/Bolts-Swift/pull/18) ([nlutsenko](https://github.com/nlutsenko)) 60 | 61 | **Fixed bugs:** 62 | 63 | - Resolve retain cycle in Task [\#19](https://github.com/BoltsFramework/Bolts-Swift/pull/19) ([mmtootmm](https://github.com/mmtootmm)) 64 | 65 | **Merged pull requests:** 66 | 67 | - Refactor continuation to be better, faster, stronger. [\#20](https://github.com/BoltsFramework/Bolts-Swift/pull/20) ([richardjrossiii](https://github.com/richardjrossiii)) 68 | - Bolts 1.2.0 🔩 [\#34](https://github.com/BoltsFramework/Bolts-Swift/pull/34) ([nlutsenko](https://github.com/nlutsenko)) 69 | - Migrate all targets to shared configurations from xctoolchain. [\#32](https://github.com/BoltsFramework/Bolts-Swift/pull/32) ([nlutsenko](https://github.com/nlutsenko)) 70 | - Add swiftlint to Travis-CI. [\#29](https://github.com/BoltsFramework/Bolts-Swift/pull/29) ([nlutsenko](https://github.com/nlutsenko)) 71 | - Split Task into multiple files. [\#24](https://github.com/BoltsFramework/Bolts-Swift/pull/24) ([richardjrossiii](https://github.com/richardjrossiii)) 72 | - Update installation instructions in README. [\#22](https://github.com/BoltsFramework/Bolts-Swift/pull/22) ([nlutsenko](https://github.com/nlutsenko)) 73 | 74 | ## [1.1.0](https://github.com/BoltsFramework/Bolts-Swift/tree/1.1.0) (2016-05-04) 75 | [Full Changelog](https://github.com/BoltsFramework/Bolts-Swift/compare/1.0.1...1.1.0) 76 | 77 | **Implemented enhancements:** 78 | 79 | - Add ability to throw errors in all Task continuations that return a Task. [\#14](https://github.com/BoltsFramework/Bolts-Swift/pull/14) ([nlutsenko](https://github.com/nlutsenko)) 80 | - Improve and add missing documentation. [\#10](https://github.com/BoltsFramework/Bolts-Swift/pull/10) ([nlutsenko](https://github.com/nlutsenko)) 81 | 82 | **Fixed bugs:** 83 | 84 | - Fix usage of CancelledError, add tests for error handling inside tasks. [\#13](https://github.com/BoltsFramework/Bolts-Swift/pull/13) ([nlutsenko](https://github.com/nlutsenko)) 85 | 86 | **Merged pull requests:** 87 | 88 | - Bolts 1.1.0 🔩 [\#16](https://github.com/BoltsFramework/Bolts-Swift/pull/16) ([nlutsenko](https://github.com/nlutsenko)) 89 | - Add more tests and fix documentation. [\#12](https://github.com/BoltsFramework/Bolts-Swift/pull/12) ([nlutsenko](https://github.com/nlutsenko)) 90 | - Use Xcode 7.3 for Travis-CI. [\#11](https://github.com/BoltsFramework/Bolts-Swift/pull/11) ([nlutsenko](https://github.com/nlutsenko)) 91 | 92 | ## [1.0.1](https://github.com/BoltsFramework/Bolts-Swift/tree/1.0.1) (2016-03-24) 93 | [Full Changelog](https://github.com/BoltsFramework/Bolts-Swift/compare/1.0.0...1.0.1) 94 | 95 | **Implemented enhancements:** 96 | 97 | - Make tests less flaky and be able to run under Swift 2.2/Xcode 7.3. [\#1](https://github.com/BoltsFramework/Bolts-Swift/pull/1) ([nlutsenko](https://github.com/nlutsenko)) 98 | 99 | **Fixed bugs:** 100 | 101 | - Task never completes [\#5](https://github.com/BoltsFramework/Bolts-Swift/issues/5) 102 | - Fix optimized away TaskCompletionSource non-try methods. [\#7](https://github.com/BoltsFramework/Bolts-Swift/pull/7) ([nlutsenko](https://github.com/nlutsenko)) 103 | 104 | **Merged pull requests:** 105 | 106 | - Bolts 1.0.1 🔩 [\#9](https://github.com/BoltsFramework/Bolts-Swift/pull/9) ([nlutsenko](https://github.com/nlutsenko)) 107 | - Add tests for release configuration in addition to Debug one. [\#8](https://github.com/BoltsFramework/Bolts-Swift/pull/8) ([nlutsenko](https://github.com/nlutsenko)) 108 | - Use common expectation wait method in tests. [\#6](https://github.com/BoltsFramework/Bolts-Swift/pull/6) ([nlutsenko](https://github.com/nlutsenko)) 109 | - README: Fix syntax in example code. [\#4](https://github.com/BoltsFramework/Bolts-Swift/pull/4) ([Lukas-Stuehrk](https://github.com/Lukas-Stuehrk)) 110 | - Fix typo in README. [\#3](https://github.com/BoltsFramework/Bolts-Swift/pull/3) ([Lukas-Stuehrk](https://github.com/Lukas-Stuehrk)) 111 | - Fix typos in README [\#2](https://github.com/BoltsFramework/Bolts-Swift/pull/2) ([richardjrossiii](https://github.com/richardjrossiii)) 112 | 113 | ## [1.0.0](https://github.com/BoltsFramework/Bolts-Swift/tree/1.0.0) (2016-03-17) 114 | 115 | 116 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bolts in Swift 2 | 3 | ![Platforms][platforms-svg] 4 | ![Swift Version][swift-version-svg] 5 | [![License][license-svg]][license-link] 6 | 7 | [![Podspec][podspec-svg]][podspec-link] 8 | [![Carthage compatible][carthage-svg]](carthage-link) 9 | [![Swift Package Manager compatible][swiftpm-svg]](swiftpm-link) 10 | 11 | [![Build Status][build-status-svg]][build-status-link] 12 | [![Coverage Status][coverage-status-svg]][coverage-status-link] 13 | 14 | Bolts is a collection of low-level libraries designed to make developing mobile apps easier. Bolts was designed by Parse and Facebook for our own internal use, and we have decided to open source these libraries to make them available to others. 15 | 16 | ## Tasks 17 | 18 | Bolts Tasks is a complete implementation of futures/promises for iOS/OS X/watchOS/tvOS and any platform that supports Swift. 19 | A task represents the result of an asynchronous operation, which typically would be returned from a function. 20 | In addition to being able to have different states `completed`/`faulted`/`cancelled` they provide these benefits: 21 | 22 | - `Tasks` consume fewer system resources, since they don't occupy a thread while waiting on other `Tasks`. 23 | - `Tasks` could be performed/chained in a row which will not create nested "pyramid" code as you would get when using only callbacks. 24 | - `Tasks` are fully composable, allowing you to perform branching, parallelism, and complex error handling, without the spaghetti code of having many named callbacks. 25 | - `Tasks` allow you to arrange code in the order that it executes, rather than having to split your logic across scattered callback functions. 26 | - `Tasks` don't depend on any particular threading model. So you can use concepts like operation queues/dispatch queues or even thread executors. 27 | - `Tasks` could be used synchronously or asynchronously, providing the same benefit of different results of any function/operation. 28 | 29 | ## Getting Started 30 | 31 | - **[CocoaPods](https://cocoapods.org)** 32 | 33 | Add the following line to your Podfile: 34 | 35 | ```ruby 36 | pod 'Bolts-Swift' 37 | ``` 38 | 39 | Run `pod install`, and you should now have the latest parse release. 40 | 41 | - **[Carthage](https://github.com/carthage/carthage)** 42 | 43 | Add the following line to your Cartfile: 44 | 45 | ``` 46 | github "BoltsFramework/Bolts-Swift" 47 | ``` 48 | 49 | Run `carthage update`, and you should now have the latest version of Bolts in your Carthage folder. 50 | 51 | - **Using Bolts as a sub-project** 52 | 53 | You can also include Bolts as a subproject inside of your application if you'd prefer, although we do not recommend this, as it will increase your indexing time significantly. To do so, just drag and drop the `BoltsSwift.xcodeproj` file into your workspace. 54 | 55 | - **Import Bolts** 56 | 57 | Now that you have the framework linked to your application - add the folowing line in every `.swift` that you want to use Bolts from: 58 | 59 | ``` 60 | import BoltsSwift 61 | ``` 62 | 63 | ## Chaining Tasks 64 | 65 | There are special methods you can call on a task which accept a closure argument and will return the task object. Because they return tasks it means you can keep calling these methods – also known as _chaining_ – to perform logic in stages. This is a powerful approach that makes your code read as a sequence of steps, while harnessing the power of asynchronous execution. Here are 3 key functions you should know: 66 | 67 | 1. Use `continueWith` to inspect the task after it has ran and perform more operations with the result 68 | 1. Use `continueWithTask` to add more work based on the result of the previous task 69 | 1. Use `continueOnSuccessWith` to perform logic only when task executed without errors 70 | 71 | For full list of available methods please see source code at **[Task+ContinueWith.swift][continueWith-source]** 72 | 73 | ### continueWith 74 | 75 | Every `Task` has a function named `continueWith`, which takes a continuation closure. A continuation will be executed when the task is complete. You can the inspect the task to check if it was successful and to get its result. 76 | 77 | ```swift 78 | save(object).continueWith { task in 79 | if task.cancelled { 80 | // Save was cancelled 81 | } else if task.faulted { 82 | // Save failed 83 | } else { 84 | // Object was successfully saved 85 | let result = task.result 86 | } 87 | } 88 | ``` 89 | 90 | ### continueOnSuccessWith 91 | 92 | In many cases, you only want to do more work if the previous task was successful, and propagate any error or cancellation to be dealt with later. To do this, use `continueOnSuccessWith` function: 93 | 94 | ```swift 95 | save(object).continueOnSuccessWith { result in 96 | // Closure receives the result of a succesfully performed task 97 | // If result is invalid throw an error which will mark task as faulted 98 | } 99 | ``` 100 | 101 | Underneath, `continueOnSuccessWith` is calling `continueOnSuccessWithTask` method which is more powerful and useful for situations where you want to spawn additional work. 102 | 103 | ### continueOnSuccessWithTask 104 | 105 | As you saw above, if you return an object from `continueWith` function – it will become a result the Task. But what if there is more work to do? If you want to call into more tasks and return their results instead – you can use `continueWithTask`. This gives you an ability to chain more asynchronous work together. 106 | 107 | In the following example we want to fetch a user profile, then fetch a profile image, and if any of these operations failed - we still want to display an placeholder image: 108 | 109 | ```swift 110 | fetchProfile(user).continueOnSuccessWithTask { task in 111 | return fetchProfileImage(task.result); 112 | }.continueWith { task in 113 | if let image = task.result { 114 | return image 115 | } 116 | return ProfileImagePlaceholder() 117 | } 118 | ``` 119 | 120 | ## Creating Tasks 121 | 122 | To create a task - you would need a `TaskCompletionSource`, which is a consumer end of any `Task`, which gives you an ability to control whether the task is completed/faulted or cancelled. 123 | After you create a `TaskCompletionSource`, you need to call `setResult()`/`setError()`/`cancel()` to trigger its continuations and change its state. 124 | 125 | ```swift 126 | func fetch(object: PFObject) -> Task { 127 | let taskCompletionSource = TaskCompletionSource() 128 | object.fetchInBackgroundWithBlock() { (object: PFObject?, error: NSError?) in 129 | if let error = error { 130 | taskCompletionSource.setError(error) 131 | } else if let object = object { 132 | taskCompletionSource.setResult(object) 133 | } else { 134 | taskCompletionSource.cancel() 135 | } 136 | } 137 | return taskCompletionSource.task 138 | } 139 | ``` 140 | 141 | ## Tasks in Parallel 142 | 143 | You can also perform several tasks in parallel and chain the result of all of them using `whenAll()` function. 144 | 145 | ```swift 146 | let query = PFQuery(className: "Comments") 147 | find(query).continueWithTask { task in 148 | var tasks: [Task] = [] 149 | task.result?.forEach { comment in 150 | tasks.append(self.deleteComment(comment)) 151 | } 152 | return Task.whenAll(tasks) 153 | }.continueOnSuccessWith { task in 154 | // All comments were deleted 155 | } 156 | ``` 157 | 158 | ## Task Executors 159 | 160 | Both `continueWith()` and `continueWithTask()` functions accept an optional executor parameter. It allows you to control how the continuation closure is executed. 161 | The default executor will dispatch to global dispatch queue, but you can provide your own executor to schedule work in a specific way. 162 | For example, if you want to continue with work on the main thread: 163 | 164 | ```swift 165 | fetch(object).continueWith(Executor.mainThread) { task in 166 | // This closure will be executor on the main application's thread 167 | } 168 | ``` 169 | 170 | ## How Do I Contribute? 171 | 172 | We want to make contributing to this project as easy and transparent as possible. Please refer to the [Contribution Guidelines][contributing]. 173 | 174 | [releases]: https://github.com/BoltsFramework/Bolts-Swift/releases 175 | [contributing]: https://github.com/BoltsFramework/Bolts-Swift/blob/master/CONTRIBUTING.md 176 | 177 | [build-status-svg]: https://img.shields.io/travis/BoltsFramework/Bolts-Swift/master.svg 178 | [build-status-link]: https://travis-ci.org/BoltsFramework/Bolts-Swift/branches 179 | 180 | [coverage-status-svg]: https://img.shields.io/codecov/c/github/BoltsFramework/Bolts-Swift/master.svg 181 | [coverage-status-link]: https://codecov.io/github/BoltsFramework/Bolts-Swift?branch=master 182 | 183 | [license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg 184 | [license-link]: https://github.com/BoltsFramework/Bolts-Swift/blob/master/LICENSE 185 | 186 | [podspec-svg]: https://img.shields.io/cocoapods/v/Bolts-Swift.svg 187 | [podspec-link]: https://cocoapods.org/pods/Bolts-Swift 188 | 189 | [carthage-svg]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat 190 | [carthage-link]: https://github.com/carthage/carthage 191 | 192 | [swiftpm-svg]: https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg?style=flat 193 | [swiftpm-link]: https://github.com/apple/swift-package-manager 194 | 195 | [platforms-svg]: http://img.shields.io/cocoapods/p/Bolts-Swift.svg?style=flat 196 | [swift-version-svg]: https://img.shields.io/badge/Swift-5-orange.svg 197 | 198 | [continueWith-source]: https://github.com/BoltsFramework/Bolts-Swift/blob/master/Sources/BoltsSwift/Task%2BContinueWith.swift 199 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/Task+ContinueWith.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | //-------------------------------------- 13 | // MARK: - ContinueWith 14 | //-------------------------------------- 15 | 16 | extension Task { 17 | /** 18 | Internal continueWithTask. This is the method that all other continuations must go through. 19 | 20 | - parameter executor: The executor to invoke the closure on. 21 | - parameter options: The options to run the closure with 22 | - parameter continuation: The closure to execute. 23 | 24 | - returns: The task resulting from the continuation 25 | */ 26 | fileprivate func continueWithTask(_ executor: Executor, 27 | options: TaskContinuationOptions, 28 | continuation: @escaping ((Task) throws -> Task) 29 | ) -> Task { 30 | let taskCompletionSource = TaskCompletionSource() 31 | let wrapperContinuation = { 32 | switch self.state { 33 | case .success where options.contains(.RunOnSuccess): fallthrough 34 | case .error where options.contains(.RunOnError): fallthrough 35 | case .cancelled where options.contains(.RunOnCancelled): 36 | executor.execute { 37 | let wrappedState = TaskState>.fromClosure { 38 | try continuation(self) 39 | } 40 | switch wrappedState { 41 | case .success(let nextTask): 42 | switch nextTask.state { 43 | case .pending: 44 | nextTask.continueWith { nextTask in 45 | taskCompletionSource.setState(nextTask.state) 46 | } 47 | default: 48 | taskCompletionSource.setState(nextTask.state) 49 | } 50 | case .error(let error): 51 | taskCompletionSource.set(error: error) 52 | case .cancelled: 53 | taskCompletionSource.cancel() 54 | default: abort() // This should never happen. 55 | } 56 | } 57 | 58 | case .success(let result as S): 59 | // This is for continueOnErrorWith - the type of the result doesn't change, so we can pass it through 60 | taskCompletionSource.set(result: result) 61 | 62 | case .error(let error): 63 | taskCompletionSource.set(error: error) 64 | 65 | case .cancelled: 66 | taskCompletionSource.cancel() 67 | 68 | default: 69 | fatalError("Task was in an invalid state \(self.state)") 70 | } 71 | } 72 | appendOrRunContinuation(wrapperContinuation) 73 | return taskCompletionSource.task 74 | } 75 | 76 | /** 77 | Enqueues a given closure to be run once this task is complete. 78 | 79 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 80 | - parameter continuation: The closure that returns the result of the task. 81 | 82 | - returns: A task that will be completed with a result from a given closure. 83 | */ 84 | @discardableResult 85 | public func continueWith(_ executor: Executor = .default, continuation: @escaping ((Task) throws -> S)) -> Task { 86 | return continueWithTask(executor) { task in 87 | let state = TaskState.fromClosure({ 88 | try continuation(task) 89 | }) 90 | return Task(state: state) 91 | } 92 | } 93 | 94 | /** 95 | Enqueues a given closure to be run once this task is complete. 96 | 97 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 98 | - parameter continuation: The closure that returns a task to chain on. 99 | 100 | - returns: A task that will be completed when a task returned from a closure is completed. 101 | */ 102 | @discardableResult 103 | public func continueWithTask(_ executor: Executor = .default, continuation: @escaping ((Task) throws -> Task)) -> Task { 104 | return continueWithTask(executor, options: .RunAlways, continuation: continuation) 105 | } 106 | } 107 | 108 | //-------------------------------------- 109 | // MARK: - ContinueOnSuccessWith 110 | //-------------------------------------- 111 | 112 | extension Task { 113 | /** 114 | Enqueues a given closure to be run once this task completes with success (has intended result). 115 | 116 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 117 | - parameter continuation: The closure that returns a task to chain on. 118 | 119 | - returns: A task that will be completed when a task returned from a closure is completed. 120 | */ 121 | @discardableResult 122 | public func continueOnSuccessWith(_ executor: Executor = .default, 123 | continuation: @escaping ((TResult) throws -> S)) -> Task { 124 | return continueOnSuccessWithTask(executor) { taskResult in 125 | let state = TaskState.fromClosure({ 126 | try continuation(taskResult) 127 | }) 128 | return Task(state: state) 129 | } 130 | } 131 | 132 | /** 133 | Enqueues a given closure to be run once this task completes with success (has intended result). 134 | 135 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 136 | - parameter continuation: The closure that returns a task to chain on. 137 | 138 | - returns: A task that will be completed when a task returned from a closure is completed. 139 | */ 140 | @discardableResult 141 | public func continueOnSuccessWithTask(_ executor: Executor = .default, 142 | continuation: @escaping ((TResult) throws -> Task)) -> Task { 143 | return continueWithTask(executor, options: .RunOnSuccess) { task in 144 | return try continuation(task.result!) 145 | } 146 | } 147 | } 148 | 149 | //-------------------------------------- 150 | // MARK: - ContinueOnErrorWith 151 | //-------------------------------------- 152 | 153 | extension Task { 154 | /** 155 | Enqueues a given closure to be run once this task completes with error. 156 | 157 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 158 | - parameter continuation: The closure that returns a task to chain on. 159 | 160 | - returns: A task that will be completed when a task returned from a closure is completed. 161 | */ 162 | @discardableResult 163 | public func continueOnErrorWith(_ executor: Executor = .default, continuation: @escaping ((E) throws -> TResult)) -> Task { 164 | return continueOnErrorWithTask(executor) { (error: E) in 165 | let state = TaskState.fromClosure({ 166 | try continuation(error) 167 | }) 168 | return Task(state: state) 169 | } 170 | } 171 | 172 | /** 173 | Enqueues a given closure to be run once this task completes with error. 174 | 175 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 176 | - parameter continuation: The closure that returns a task to chain on. 177 | 178 | - returns: A task that will be completed when a task returned from a closure is completed. 179 | */ 180 | @discardableResult 181 | public func continueOnErrorWith(_ executor: Executor = .default, continuation: @escaping ((Error) throws -> TResult)) -> Task { 182 | return continueOnErrorWithTask(executor) { (error: Error) in 183 | let state = TaskState.fromClosure({ 184 | try continuation(error) 185 | }) 186 | return Task(state: state) 187 | } 188 | } 189 | 190 | /** 191 | Enqueues a given closure to be run once this task completes with error. 192 | 193 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 194 | - parameter continuation: The closure that returns a task to chain on. 195 | 196 | - returns: A task that will be completed when a task returned from a closure is completed. 197 | */ 198 | @discardableResult 199 | public func continueOnErrorWithTask(_ executor: Executor = .default, continuation: @escaping ((E) throws -> Task)) -> Task { 200 | return continueOnErrorWithTask(executor) { (error: Error) in 201 | if let error = error as? E { 202 | return try continuation(error) 203 | } 204 | return Task(state: .error(error)) 205 | } 206 | } 207 | 208 | /** 209 | Enqueues a given closure to be run once this task completes with error. 210 | 211 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 212 | - parameter continuation: The closure that returns a task to chain on. 213 | 214 | - returns: A task that will be completed when a task returned from a closure is completed. 215 | */ 216 | @discardableResult 217 | public func continueOnErrorWithTask(_ executor: Executor = .default, continuation: @escaping ((Error) throws -> Task)) -> Task { 218 | return continueWithTask(executor, options: .RunOnError) { task in 219 | return try continuation(task.error!) 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /Sources/BoltsSwift/Task.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import Foundation 11 | 12 | enum TaskState { 13 | case pending 14 | case success(TResult) 15 | case error(Error) 16 | case cancelled 17 | 18 | static func fromClosure(_ closure: () throws -> TResult) -> TaskState { 19 | do { 20 | return .success(try closure()) 21 | } catch is CancelledError { 22 | return .cancelled 23 | } catch { 24 | return .error(error) 25 | } 26 | } 27 | } 28 | 29 | struct TaskContinuationOptions: OptionSet { 30 | let rawValue: Int 31 | init(rawValue: Int) { 32 | self.rawValue = rawValue 33 | } 34 | 35 | static let RunOnSuccess = TaskContinuationOptions(rawValue: 1 << 0) 36 | static let RunOnError = TaskContinuationOptions(rawValue: 1 << 1) 37 | static let RunOnCancelled = TaskContinuationOptions(rawValue: 1 << 2) 38 | 39 | static let RunAlways: TaskContinuationOptions = [ .RunOnSuccess, .RunOnError, .RunOnCancelled ] 40 | } 41 | 42 | //-------------------------------------- 43 | // MARK: - Task 44 | //-------------------------------------- 45 | 46 | /// 47 | /// The consumer view of a Task. 48 | /// Task has methods to inspect the state of the task, and to add continuations to be run once the task is complete. 49 | /// 50 | public final class Task { 51 | public typealias Continuation = () -> Void 52 | 53 | fileprivate let synchronizationQueue = DispatchQueue(label: "com.bolts.task", attributes: DispatchQueue.Attributes.concurrent) 54 | fileprivate var _completedCondition: NSCondition? 55 | 56 | fileprivate var _state: TaskState = .pending 57 | fileprivate var _continuations: [Continuation] = Array() 58 | 59 | // MARK: Initializers 60 | 61 | init() {} 62 | 63 | init(state: TaskState) { 64 | _state = state 65 | } 66 | 67 | /** 68 | Creates a task that is already completed with the given result. 69 | 70 | - parameter result: The task result. 71 | */ 72 | public init(_ result: TResult) { 73 | _state = .success(result) 74 | } 75 | 76 | /** 77 | Initializes a task that is already completed with the given error. 78 | 79 | - parameter error: The task error. 80 | */ 81 | public init(error: Error) { 82 | _state = .error(error) 83 | } 84 | 85 | /** 86 | Creates a cancelled task. 87 | 88 | - returns: A cancelled task. 89 | */ 90 | public class func cancelledTask() -> Self { 91 | // Swift prevents this method from being called `cancelled` due to the `cancelled` instance var. This is most likely a bug. 92 | return self.init(state: .cancelled) 93 | } 94 | 95 | class func emptyTask() -> Task { 96 | return Task(state: .success(())) 97 | } 98 | 99 | // MARK: Execute 100 | 101 | /** 102 | Creates a task that will complete with the result of the given closure. 103 | 104 | - note: The closure cannot make the returned task to fail. Use the other `execute` overload for this. 105 | 106 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 107 | - parameter closure: The closure that returns the result of the task. 108 | The returned task will complete when the closure completes. 109 | */ 110 | public convenience init(_ executor: Executor = .default, closure: @escaping (() throws -> TResult)) { 111 | self.init(state: .pending) 112 | executor.execute { 113 | self.trySet(state: TaskState.fromClosure(closure)) 114 | } 115 | } 116 | 117 | /** 118 | Creates a task that will continue with the task returned by the given closure. 119 | 120 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 121 | - parameter closure: The closure that returns the continuation task. 122 | The returned task will complete when the continuation task completes. 123 | 124 | - returns: A task that will continue with the task returned by the given closure. 125 | */ 126 | public class func execute(_ executor: Executor = .default, closure: @escaping (() throws -> TResult)) -> Task { 127 | return Task(executor, closure: closure) 128 | } 129 | 130 | /** 131 | Creates a task that will continue with the task returned by the given closure. 132 | 133 | - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. 134 | - parameter closure: The closure that returns the continuation task. 135 | The returned task will complete when the continuation task completes. 136 | 137 | - returns: A task that will continue with the task returned by the given closure. 138 | */ 139 | public class func executeWithTask(_ executor: Executor = .default, closure: @escaping (() throws -> Task)) -> Task { 140 | return emptyTask().continueWithTask(executor) { _ in 141 | return try closure() 142 | } 143 | } 144 | 145 | // MARK: State Accessors 146 | 147 | /// Whether this task is completed. A completed task can also be faulted or cancelled. 148 | public var completed: Bool { 149 | switch state { 150 | case .pending: 151 | return false 152 | default: 153 | return true 154 | } 155 | } 156 | 157 | /// Whether this task has completed due to an error or exception. A `faulted` task is also completed. 158 | public var faulted: Bool { 159 | switch state { 160 | case .error: 161 | return true 162 | default: 163 | return false 164 | } 165 | } 166 | 167 | /// Whether this task has been cancelled. A `cancelled` task is also completed. 168 | public var cancelled: Bool { 169 | switch state { 170 | case .cancelled: 171 | return true 172 | default: 173 | return false 174 | } 175 | } 176 | 177 | /// The result of a successful task. Won't be set until the task completes with a `result`. 178 | public var result: TResult? { 179 | switch state { 180 | case .success(let result): 181 | return result 182 | default: 183 | break 184 | } 185 | return nil 186 | } 187 | 188 | /// The error of a errored task. Won't be set until the task completes with `error`. 189 | public var error: Error? { 190 | switch state { 191 | case .error(let error): 192 | return error 193 | default: 194 | break 195 | } 196 | return nil 197 | } 198 | 199 | /** 200 | Waits until this operation is completed. 201 | 202 | This method is inefficient and consumes a thread resource while it's running. 203 | It should be avoided. This method logs a warning message if it is used on the main thread. 204 | */ 205 | public func waitUntilCompleted() { 206 | if Thread.isMainThread { 207 | debugPrint("Warning: A long-running operation is being executed on the main thread waiting on \(self).") 208 | } 209 | 210 | var conditon: NSCondition? 211 | synchronizationQueue.sync(flags: .barrier, execute: { 212 | if case .pending = self._state { 213 | conditon = self._completedCondition ?? NSCondition() 214 | self._completedCondition = conditon 215 | } 216 | }) 217 | 218 | guard let condition = conditon else { 219 | // Task should have been completed 220 | precondition(completed) 221 | return 222 | } 223 | 224 | condition.lock() 225 | while !completed { 226 | condition.wait() 227 | } 228 | condition.unlock() 229 | 230 | synchronizationQueue.sync(flags: .barrier, execute: { 231 | self._completedCondition = nil 232 | }) 233 | } 234 | 235 | // MARK: State Change 236 | 237 | @discardableResult 238 | func trySet(state: TaskState) -> Bool { 239 | var stateChanged = false 240 | 241 | var continuations: [Continuation]? 242 | var completedCondition: NSCondition? 243 | synchronizationQueue.sync(flags: .barrier, execute: { 244 | switch self._state { 245 | case .pending: 246 | stateChanged = true 247 | self._state = state 248 | continuations = self._continuations 249 | completedCondition = self._completedCondition 250 | self._continuations.removeAll() 251 | default: 252 | break 253 | } 254 | }) 255 | if stateChanged { 256 | completedCondition?.lock() 257 | completedCondition?.broadcast() 258 | completedCondition?.unlock() 259 | 260 | for continuation in continuations! { 261 | continuation() 262 | } 263 | } 264 | 265 | return stateChanged 266 | } 267 | 268 | // MARK: Internal 269 | 270 | func appendOrRunContinuation(_ continuation: @escaping Continuation) { 271 | var runContinuation = false 272 | synchronizationQueue.sync(flags: .barrier, execute: { 273 | switch self._state { 274 | case .pending: 275 | self._continuations.append(continuation) 276 | default: 277 | runContinuation = true 278 | } 279 | }) 280 | if runContinuation { 281 | continuation() 282 | } 283 | } 284 | 285 | var state: TaskState { 286 | var value: TaskState? 287 | synchronizationQueue.sync { 288 | value = self._state 289 | } 290 | return value! 291 | } 292 | } 293 | 294 | //-------------------------------------- 295 | // MARK: - Description 296 | //-------------------------------------- 297 | 298 | extension Task: CustomStringConvertible, CustomDebugStringConvertible { 299 | /// A textual representation of `self`. 300 | public var description: String { 301 | return "Task: \(self.state)" 302 | } 303 | 304 | /// A textual representation of `self`, suitable for debugging. 305 | public var debugDescription: String { 306 | return "Task: \(self.state)" 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /Tests/TaskTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | import XCTest 11 | import BoltsSwift 12 | 13 | class TaskTests: XCTestCase { 14 | 15 | // MARK: Initializers 16 | 17 | func testWithResult() { 18 | let task = Task(name) 19 | 20 | XCTAssertNotNil(task.result) 21 | XCTAssertEqual(task.result, name) 22 | XCTAssertTrue(task.completed) 23 | XCTAssertFalse(task.faulted) 24 | XCTAssertFalse(task.cancelled) 25 | XCTAssertNil(task.error) 26 | } 27 | 28 | func testWithError() { 29 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 30 | let task = Task(error: error) 31 | 32 | XCTAssertNil(task.result) 33 | XCTAssertTrue(task.completed) 34 | XCTAssertTrue(task.faulted) 35 | XCTAssertFalse(task.cancelled) 36 | XCTAssertNotNil(task.error) 37 | XCTAssertEqual(task.error as NSError?, error) 38 | } 39 | 40 | func testCancelledTask() { 41 | let task = Task.cancelledTask() 42 | 43 | XCTAssertNil(task.result) 44 | XCTAssertTrue(task.completed) 45 | XCTAssertFalse(task.faulted) 46 | XCTAssertTrue(task.cancelled) 47 | XCTAssertNil(task.error) 48 | } 49 | 50 | // MARK: Task with Delay 51 | 52 | func testWithDelay() { 53 | let expectation = self.expectation(description: name) 54 | let task = Task.withDelay(0.01) 55 | task.continueWith { _ in 56 | expectation.fulfill() 57 | } 58 | 59 | XCTAssertFalse(task.completed) 60 | waitForTestExpectations() 61 | } 62 | 63 | // MARK: Execute 64 | 65 | func testExecuteWithClosureReturningNil() { 66 | let expectation = self.expectation(description: name) 67 | let task = Task { 68 | expectation.fulfill() 69 | return "Hello, World!" 70 | } 71 | waitForTestExpectations() 72 | XCTAssertEqual(task.result, "Hello, World!") 73 | } 74 | 75 | func testConstructorWithClosureReturningValue() { 76 | let expectation = self.expectation(description: name) 77 | let task = Task { 78 | expectation.fulfill() 79 | return self.name 80 | } 81 | waitForTestExpectations() 82 | XCTAssertNotNil(task.result) 83 | XCTAssertEqual(task.result, name) 84 | } 85 | 86 | func testExecuteWithClosureReturningValue() { 87 | let expectation = self.expectation(description: name) 88 | let task = Task.execute { 89 | expectation.fulfill() 90 | return self.name 91 | } 92 | waitForTestExpectations() 93 | XCTAssertNotNil(task.result) 94 | XCTAssertEqual(task.result, name) 95 | } 96 | 97 | func testExecuteWithClosureReturningTaskWithResult() { 98 | let expectation = self.expectation(description: name) 99 | let task = Task.executeWithTask { () -> Task in 100 | expectation.fulfill() 101 | return Task(10) 102 | } 103 | waitForTestExpectations() 104 | XCTAssertNotNil(task.result) 105 | XCTAssertEqual(task.result, 10) 106 | } 107 | 108 | func testExecuteWithClosureReturningCancelledTask() { 109 | let expectation = self.expectation(description: name) 110 | let task = Task.executeWithTask { () -> Task in 111 | expectation.fulfill() 112 | return Task.cancelledTask() 113 | } 114 | waitForTestExpectations() 115 | XCTAssertTrue(task.cancelled) 116 | } 117 | 118 | func textExecuteWithClosureThrowingError() { 119 | let expectation = self.expectation(description: name) 120 | let task = Task.execute { 121 | defer { 122 | expectation.fulfill() 123 | } 124 | throw NSError(domain: "com.bolts", code: 1, userInfo: nil) 125 | } 126 | waitForTestExpectations() 127 | XCTAssertNotNil(task.error) 128 | } 129 | 130 | func testExecuteWithClosureThrowingCancelledError() { 131 | let expectation = self.expectation(description: name) 132 | let task = Task.execute { 133 | defer { 134 | expectation.fulfill() 135 | } 136 | throw CancelledError() 137 | } 138 | waitForTestExpectations() 139 | XCTAssertTrue(task.cancelled) 140 | XCTAssertNil(task.error) 141 | } 142 | 143 | func textExecuteWithTaskClosureThrowingError() { 144 | let expectation = self.expectation(description: name) 145 | let task = Task.executeWithTask { 146 | defer { 147 | expectation.fulfill() 148 | } 149 | throw NSError(domain: "com.bolts", code: 1, userInfo: nil) 150 | } 151 | waitForTestExpectations() 152 | XCTAssertNotNil(task.error) 153 | } 154 | 155 | func testExecuteWithTaskClosureThrowingCancelledError() { 156 | let expectation = self.expectation(description: name) 157 | let task = Task.executeWithTask { 158 | defer { 159 | expectation.fulfill() 160 | } 161 | throw CancelledError() 162 | } 163 | waitForTestExpectations() 164 | XCTAssertTrue(task.cancelled) 165 | XCTAssertNil(task.error) 166 | } 167 | 168 | // MARK: Continuations 169 | 170 | func testContinueWithOnSucessfulTaskByReturningResult() { 171 | let expectation = self.expectation(description: name) 172 | let initialTask = Task(1) 173 | 174 | let continuationTask = initialTask.continueWith { task -> String? in 175 | XCTAssertTrue(task === initialTask) 176 | return self.name 177 | } 178 | 179 | continuationTask.continueOnSuccessWith { 180 | XCTAssertEqual($0, self.name) 181 | expectation.fulfill() 182 | } 183 | waitForTestExpectations() 184 | } 185 | 186 | func testContinueWithOnErroredTaskByReturningResult() { 187 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 188 | let expectation = self.expectation(description: name) 189 | let initialTask = Task(error: error) 190 | 191 | let continuationTask = initialTask.continueWith { task -> String? in 192 | XCTAssertTrue(task === initialTask) 193 | return self.name 194 | } 195 | 196 | continuationTask.continueOnSuccessWith { 197 | XCTAssertEqual($0, self.name) 198 | expectation.fulfill() 199 | } 200 | waitForTestExpectations() 201 | } 202 | 203 | func testContinueWithOnCancelledTaskByReturningResult() { 204 | let expectation = self.expectation(description: name) 205 | let initialTask = Task.cancelledTask() 206 | 207 | let continuationTask = initialTask.continueWith { task -> String? in 208 | XCTAssertTrue(task === initialTask) 209 | return self.name 210 | } 211 | 212 | continuationTask.continueOnSuccessWith { 213 | XCTAssertEqual($0, self.name) 214 | expectation.fulfill() 215 | } 216 | waitForTestExpectations() 217 | } 218 | 219 | func testContinueWithWithExecutor() { 220 | let expectation = self.expectation(description: name) 221 | let initialTask = Task.cancelledTask() 222 | let executorExpectation = self.expectation(description: "executor") 223 | 224 | let executor = Executor.closure { 225 | $0() 226 | executorExpectation.fulfill() 227 | } 228 | 229 | let continuationTask = initialTask.continueWith(executor) { task -> String? in 230 | XCTAssertTrue(task === initialTask) 231 | return self.name 232 | } 233 | 234 | continuationTask.continueOnSuccessWith { 235 | XCTAssertEqual($0, self.name) 236 | expectation.fulfill() 237 | } 238 | waitForTestExpectations() 239 | } 240 | 241 | func testContinueWithByReturningNilResult() { 242 | let expectation = self.expectation(description: name) 243 | let initialTask = Task(1) 244 | 245 | let continuationTask = initialTask.continueWith { task -> String? in 246 | XCTAssertTrue(task === initialTask) 247 | return nil 248 | } 249 | 250 | continuationTask.continueOnSuccessWith { 251 | XCTAssertNil($0) 252 | expectation.fulfill() 253 | } 254 | waitForTestExpectations() 255 | } 256 | 257 | func testContinueWithByReturningTask() { 258 | let expectation = self.expectation(description: name) 259 | let firstTask = Task(1) 260 | let secondTask = Task(name) 261 | 262 | let continuationTask = firstTask.continueWithTask { task -> Task in 263 | XCTAssertTrue(task === firstTask) 264 | return secondTask 265 | } 266 | 267 | XCTAssertTrue(continuationTask !== secondTask) 268 | continuationTask.continueOnSuccessWith { 269 | XCTAssertEqual($0, self.name) 270 | expectation.fulfill() 271 | } 272 | waitForTestExpectations() 273 | } 274 | 275 | func testContinueWithByReturningNilTask() { 276 | let expectation = self.expectation(description: name) 277 | let initialTask = Task(1) 278 | 279 | let continuationTask = initialTask.continueWith { task in 280 | XCTAssertTrue(task === initialTask) 281 | } 282 | 283 | continuationTask.continueWith { _ in 284 | expectation.fulfill() 285 | } 286 | waitForTestExpectations() 287 | } 288 | 289 | func testChainedContinueWithFunctions() { 290 | let expectation = self.expectation(description: name) 291 | var count = 0 292 | 293 | Task.cancelledTask().continueWith { _ -> String? in 294 | count += 1 295 | XCTAssertEqual(count, 1) 296 | return nil 297 | }.continueWith { _ -> String? in 298 | count += 1 299 | XCTAssertEqual(count, 2) 300 | return nil 301 | }.continueWith { _ -> String? in 302 | count += 1 303 | XCTAssertEqual(count, 3) 304 | return nil 305 | }.continueWith { _ -> String? in 306 | count += 1 307 | XCTAssertEqual(count, 4) 308 | return nil 309 | }.continueWith { _ -> String? in 310 | count += 1 311 | XCTAssertEqual(count, 5) 312 | expectation.fulfill() 313 | return nil 314 | } 315 | 316 | waitForTestExpectations() 317 | } 318 | 319 | func testChainedContinueWithWithAsyncExecutor() { 320 | let expectation = self.expectation(description: name) 321 | let executor = Executor.queue(DispatchQueue.global(qos: .default)) 322 | var count = 0 323 | 324 | Task.cancelledTask().continueWith(executor) { _ in 325 | count += 1 326 | XCTAssertEqual(count, 1) 327 | }.continueWith(executor) { _ in 328 | count += 1 329 | XCTAssertEqual(count, 2) 330 | }.continueWith(executor) { _ in 331 | count += 1 332 | XCTAssertEqual(count, 3) 333 | }.continueWith(executor) { _ in 334 | count += 1 335 | XCTAssertEqual(count, 4) 336 | }.continueWith(executor) { _ in 337 | count += 1 338 | XCTAssertEqual(count, 5) 339 | expectation.fulfill() 340 | } 341 | 342 | waitForTestExpectations() 343 | } 344 | 345 | //-------------------------------------- 346 | // MARK: - continueOnError 347 | //-------------------------------------- 348 | 349 | func testContinueOnGenericErrorRecovers() { 350 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 351 | let expectation = self.expectation(description: name) 352 | let initialTask = Task(error: error) 353 | 354 | let continuationTask = initialTask.continueOnErrorWith { taskError -> String? in 355 | XCTAssertEqual(taskError as NSError, error) 356 | return self.name 357 | } 358 | continuationTask.continueOnSuccessWith { 359 | XCTAssertEqual($0, self.name) 360 | expectation.fulfill() 361 | } 362 | waitForTestExpectations() 363 | } 364 | 365 | func testContinueOnSpecificErrorRecovers() { 366 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 367 | let expectation = self.expectation(description: name) 368 | let initialTask = Task(error: error) 369 | 370 | let continuationTask = initialTask.continueOnErrorWith { (taskError: NSError) -> String? in 371 | XCTAssertEqual(taskError, error) 372 | return self.name 373 | } 374 | continuationTask.continueOnSuccessWith { 375 | XCTAssertEqual($0, self.name) 376 | expectation.fulfill() 377 | } 378 | waitForTestExpectations() 379 | } 380 | 381 | //-------------------------------------- 382 | // MARK: - WhenAll 383 | //-------------------------------------- 384 | 385 | func testWhenAllTasksEmptyArray() { 386 | let tasks: [Task] = [] 387 | 388 | let expectation = self.expectation(description: name) 389 | Task.whenAll(tasks).continueWith { task in 390 | XCTAssertTrue(task.completed) 391 | XCTAssertFalse(task.faulted) 392 | XCTAssertFalse(task.cancelled) 393 | expectation.fulfill() 394 | } 395 | waitForExpectations(timeout: 5.0, handler: nil) 396 | } 397 | 398 | func testWhenAllTasksSuccess() { 399 | var tasks = [Task]() 400 | var count: Int32 = 0 401 | 402 | for i in 1...20 { 403 | let task = Task.withDelay(0.5) 404 | .continueWith(continuation: { _ -> Int in 405 | OSAtomicIncrement32(&count) 406 | return i 407 | }) 408 | tasks.append(task) 409 | } 410 | 411 | let expectation = self.expectation(description: name) 412 | let task = Task.whenAll(tasks).continueWith { task in 413 | XCTAssertEqual(count, Int32(tasks.count)) 414 | XCTAssertTrue(task.completed) 415 | XCTAssertFalse(task.faulted) 416 | XCTAssertFalse(task.cancelled) 417 | expectation.fulfill() 418 | } 419 | 420 | XCTAssertFalse(task.completed) 421 | XCTAssertFalse(task.faulted) 422 | XCTAssertFalse(task.cancelled) 423 | 424 | waitForExpectations(timeout: 5.0, handler: nil) 425 | } 426 | 427 | func testWhenAllTasksWithResultSuccess() { 428 | var tasks = [Task]() 429 | var count: Int32 = 0 430 | let executor = Executor.queue(DispatchQueue.global(qos: .default)) 431 | 432 | for i in 1...20 { 433 | let task = Task.withDelay(0.5) 434 | .continueWith(executor, continuation: { _ -> Int in 435 | OSAtomicIncrement32(&count) 436 | return i 437 | }) 438 | tasks.append(task) 439 | } 440 | 441 | let expectation = self.expectation(description: name) 442 | let task = Task.whenAllResult(tasks).continueWith { task in 443 | XCTAssertEqual(count, Int32(tasks.count)) 444 | XCTAssertTrue(task.completed) 445 | XCTAssertFalse(task.faulted) 446 | XCTAssertFalse(task.cancelled) 447 | XCTAssertEqual(Int32(task.result!.count), count) 448 | expectation.fulfill() 449 | } 450 | 451 | XCTAssertFalse(task.completed) 452 | XCTAssertFalse(task.faulted) 453 | XCTAssertFalse(task.cancelled) 454 | 455 | waitForTestExpectations() 456 | } 457 | 458 | func testWhenAllTasksWithCancel() { 459 | var tasks = [Task]() 460 | var count: Int32 = 0 461 | let executor = Executor.queue(DispatchQueue.global(qos: .default)) 462 | 463 | for i in 1...20 { 464 | let task = Task.withDelay(0.5) 465 | .continueWithTask(executor, continuation: { _ -> Task in 466 | OSAtomicIncrement32(&count) 467 | if i == 20 { 468 | return Task.cancelledTask() 469 | } 470 | return Task(i) 471 | }) 472 | tasks.append(task) 473 | } 474 | 475 | let expectation = self.expectation(description: name) 476 | let task = Task.whenAllResult(tasks).continueWith { task in 477 | XCTAssertEqual(count, Int32(tasks.count)) 478 | XCTAssertTrue(task.completed) 479 | XCTAssertFalse(task.faulted) 480 | XCTAssertTrue(task.cancelled) 481 | expectation.fulfill() 482 | } 483 | 484 | XCTAssertFalse(task.completed) 485 | XCTAssertFalse(task.faulted) 486 | XCTAssertFalse(task.cancelled) 487 | 488 | waitForTestExpectations() 489 | } 490 | 491 | func testWhenAllTasksError() { 492 | var tasks: [Task] = [] 493 | var count: Int32 = 0 494 | 495 | for i in 1...20 { 496 | let task = Task.withDelay(0.5) 497 | .continueWith(continuation: { _ in 498 | OSAtomicIncrement32(&count) 499 | throw NSError(domain: "bolts", code: i, userInfo: nil) 500 | }) 501 | tasks.append(task) 502 | } 503 | 504 | let expectation = self.expectation(description: name) 505 | let task = Task.whenAll(tasks).continueWith { task in 506 | XCTAssertEqual(count, Int32(tasks.count)) 507 | XCTAssertTrue(task.completed) 508 | XCTAssertTrue(task.faulted) 509 | XCTAssertFalse(task.cancelled) 510 | guard let error = task.error as? AggregateError else { 511 | XCTFail("Not an aggregate error returned.") 512 | expectation.fulfill() 513 | return 514 | } 515 | XCTAssertEqual(error.errors.count, Int(count)) 516 | expectation.fulfill() 517 | } 518 | 519 | XCTAssertFalse(task.completed) 520 | XCTAssertFalse(task.faulted) 521 | XCTAssertFalse(task.cancelled) 522 | 523 | waitForExpectations(timeout: 5.0, handler: nil) 524 | } 525 | 526 | // MARK: When Any 527 | 528 | func testWhenAnyTasksSuccess() { 529 | var tasks = [Task]() 530 | var count: Int32 = 0 531 | let executor = Executor.queue(DispatchQueue.global(qos: .default)) 532 | 533 | tasks.append(Task.withDelay(0.2).continueWith { _ in 534 | // Use max value of Int32, so we can use the same code across both 32 and 64 bit archs. 535 | return Int(arc4random_uniform(UInt32(Int32.max))) 536 | }) 537 | for i in 1...20 { 538 | let task = Task.withDelay(0.5) 539 | .continueWith(executor, continuation: { _ -> Int in 540 | OSAtomicIncrement32(&count) 541 | return i 542 | }) 543 | tasks.append(task) 544 | } 545 | 546 | let expectation = self.expectation(description: name) 547 | let task = Task.whenAny(tasks).continueWith { task in 548 | XCTAssertNotEqual(count, Int32(tasks.count)) 549 | XCTAssertTrue(task.completed) 550 | XCTAssertFalse(task.faulted) 551 | XCTAssertFalse(task.cancelled) 552 | expectation.fulfill() 553 | } 554 | 555 | XCTAssertFalse(task.completed) 556 | XCTAssertFalse(task.faulted) 557 | XCTAssertFalse(task.cancelled) 558 | 559 | waitForTestExpectations() 560 | } 561 | 562 | func testWhenAnyTasksWithErrors() { 563 | var tasks = [Task]() 564 | var count: Int32 = 0 565 | 566 | let executor = Executor.queue(DispatchQueue.global(qos: .default)) 567 | let error = NSError(domain: "com.bolts", code: 1, userInfo: nil) 568 | 569 | for i in 1...20 { 570 | let task = Task.withDelay(Double(i) * 0.5) 571 | .continueWithTask(executor, continuation: { _ -> Task in 572 | OSAtomicIncrement32(&count) 573 | return Task(error: error) 574 | }) 575 | tasks.append(task) 576 | } 577 | 578 | let expectation = self.expectation(description: name) 579 | let task = Task.whenAny(tasks).continueWith { task in 580 | XCTAssertNotEqual(count, Int32(tasks.count)) 581 | XCTAssertTrue(task.completed) 582 | XCTAssertFalse(task.faulted) 583 | XCTAssertFalse(task.cancelled) 584 | expectation.fulfill() 585 | } 586 | 587 | XCTAssertFalse(task.completed) 588 | XCTAssertFalse(task.faulted) 589 | XCTAssertFalse(task.cancelled) 590 | 591 | waitForTestExpectations() 592 | } 593 | 594 | func testWhenAnyTasksWithCancel() { 595 | var tasks = [Task]() 596 | var count: Int32 = 0 597 | 598 | let executor = Executor.queue(DispatchQueue.global(qos: .default)) 599 | 600 | for i in 1...20 { 601 | let task = Task.withDelay(Double(i) * 0.5) 602 | .continueWithTask(executor, continuation: { _ -> Task in 603 | OSAtomicIncrement32(&count) 604 | return Task.cancelledTask() 605 | }) 606 | tasks.append(task) 607 | } 608 | 609 | let expectation = self.expectation(description: name) 610 | let task = Task.whenAny(tasks).continueWith { task in 611 | XCTAssertNotEqual(count, Int32(tasks.count)) 612 | XCTAssertTrue(task.completed) 613 | XCTAssertFalse(task.faulted) 614 | XCTAssertFalse(task.cancelled) 615 | expectation.fulfill() 616 | } 617 | 618 | XCTAssertFalse(task.completed) 619 | XCTAssertFalse(task.faulted) 620 | XCTAssertFalse(task.cancelled) 621 | 622 | waitForTestExpectations() 623 | } 624 | 625 | // MARK: Wait 626 | 627 | func testTaskWait() { 628 | Task.withDelay(0.5).waitUntilCompleted() 629 | } 630 | 631 | func testCompletedTaskWait() { 632 | Task(self.name).waitUntilCompleted() 633 | } 634 | 635 | func testTaskChainWait() { 636 | var count = 0 637 | 638 | Task.cancelledTask().continueWith { _ in 639 | count += 1 640 | XCTAssertEqual(count, 1) 641 | }.continueWith { _ in 642 | count += 1 643 | XCTAssertEqual(count, 2) 644 | }.continueWith { _ in 645 | count += 1 646 | XCTAssertEqual(count, 3) 647 | }.continueWith { _ in 648 | count += 1 649 | XCTAssertEqual(count, 4) 650 | }.continueWith { _ in 651 | count += 1 652 | XCTAssertEqual(count, 5) 653 | }.waitUntilCompleted() 654 | XCTAssertEqual(count, 5) 655 | } 656 | } 657 | -------------------------------------------------------------------------------- /BoltsSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 065894EF1C9A9391000FDDA6 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300651C93AF7300E1A1ED /* Task.swift */; }; 11 | 065894F01C9A9391000FDDA6 /* TaskCompletionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */; }; 12 | 065894F11C9A9391000FDDA6 /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300641C93AF7300E1A1ED /* Executor.swift */; }; 13 | 065894F21C9A9391000FDDA6 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300631C93AF7300E1A1ED /* Errors.swift */; }; 14 | 065894F51C9A93B7000FDDA6 /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300641C93AF7300E1A1ED /* Executor.swift */; }; 15 | 065894F61C9A93B7000FDDA6 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300651C93AF7300E1A1ED /* Task.swift */; }; 16 | 065894F71C9A93B7000FDDA6 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300631C93AF7300E1A1ED /* Errors.swift */; }; 17 | 065894F81C9A93B7000FDDA6 /* TaskCompletionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */; }; 18 | 065895121C9A947B000FDDA6 /* ExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300751C93AF9F00E1A1ED /* ExecutorTests.swift */; }; 19 | 065895131C9A947B000FDDA6 /* TaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300781C93AF9F00E1A1ED /* TaskTests.swift */; }; 20 | 065895141C9A947B000FDDA6 /* TaskCompletionSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300771C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift */; }; 21 | 0658951F1C9A9496000FDDA6 /* BoltsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 065894FF1C9A93B7000FDDA6 /* BoltsSwift.framework */; }; 22 | 810AB3201C9B1AC3005B6184 /* XCTestCase+TestName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810AB31F1C9B1AC3005B6184 /* XCTestCase+TestName.swift */; }; 23 | 810AB3211C9B1AC3005B6184 /* XCTestCase+TestName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810AB31F1C9B1AC3005B6184 /* XCTestCase+TestName.swift */; }; 24 | 810AB3221C9B1AC3005B6184 /* XCTestCase+TestName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810AB31F1C9B1AC3005B6184 /* XCTestCase+TestName.swift */; }; 25 | 81CC14F71A9BE0A100B28F86 /* BoltsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81CC14EC1A9BE0A100B28F86 /* BoltsSwift.framework */; }; 26 | 81D300681C93AF7300E1A1ED /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300631C93AF7300E1A1ED /* Errors.swift */; }; 27 | 81D300691C93AF7300E1A1ED /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300631C93AF7300E1A1ED /* Errors.swift */; }; 28 | 81D3006A1C93AF7300E1A1ED /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300641C93AF7300E1A1ED /* Executor.swift */; }; 29 | 81D3006B1C93AF7300E1A1ED /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300641C93AF7300E1A1ED /* Executor.swift */; }; 30 | 81D3006C1C93AF7300E1A1ED /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300651C93AF7300E1A1ED /* Task.swift */; }; 31 | 81D3006D1C93AF7300E1A1ED /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300651C93AF7300E1A1ED /* Task.swift */; }; 32 | 81D3006E1C93AF7300E1A1ED /* TaskCompletionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */; }; 33 | 81D3006F1C93AF7300E1A1ED /* TaskCompletionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */; }; 34 | 81D300791C93AF9F00E1A1ED /* ExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300751C93AF9F00E1A1ED /* ExecutorTests.swift */; }; 35 | 81D3007A1C93AF9F00E1A1ED /* ExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300751C93AF9F00E1A1ED /* ExecutorTests.swift */; }; 36 | 81D3007D1C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300771C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift */; }; 37 | 81D3007E1C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300771C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift */; }; 38 | 81D3007F1C93AF9F00E1A1ED /* TaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300781C93AF9F00E1A1ED /* TaskTests.swift */; }; 39 | 81D300801C93AF9F00E1A1ED /* TaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81D300781C93AF9F00E1A1ED /* TaskTests.swift */; }; 40 | 87FEF3721A9085FA00C60678 /* BoltsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87FEF3661A9085FA00C60678 /* BoltsSwift.framework */; }; 41 | F569C0C11CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; }; 42 | F569C0C21CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; }; 43 | F569C0C31CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; }; 44 | F569C0C41CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */; }; 45 | F569C0CC1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; }; 46 | F569C0CD1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; }; 47 | F569C0CE1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; }; 48 | F569C0CF1CFF6AEE000749B6 /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */; }; 49 | F569C0D71CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; }; 50 | F569C0D81CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; }; 51 | F569C0D91CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; }; 52 | F569C0DA1CFF6B18000749B6 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */; }; 53 | F569C0E11CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; }; 54 | F569C0E21CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; }; 55 | F569C0E31CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; }; 56 | F569C0E41CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */; }; 57 | /* End PBXBuildFile section */ 58 | 59 | /* Begin PBXContainerItemProxy section */ 60 | 0658951D1C9A948E000FDDA6 /* PBXContainerItemProxy */ = { 61 | isa = PBXContainerItemProxy; 62 | containerPortal = 87FEF35D1A9085FA00C60678 /* Project object */; 63 | proxyType = 1; 64 | remoteGlobalIDString = 065894F31C9A93B7000FDDA6; 65 | remoteInfo = "BoltsSwift-tvOS"; 66 | }; 67 | 81CC14F81A9BE0A100B28F86 /* PBXContainerItemProxy */ = { 68 | isa = PBXContainerItemProxy; 69 | containerPortal = 87FEF35D1A9085FA00C60678 /* Project object */; 70 | proxyType = 1; 71 | remoteGlobalIDString = 81CC14EB1A9BE0A100B28F86; 72 | remoteInfo = "Bolts-Mac"; 73 | }; 74 | 87FEF3731A9085FA00C60678 /* PBXContainerItemProxy */ = { 75 | isa = PBXContainerItemProxy; 76 | containerPortal = 87FEF35D1A9085FA00C60678 /* Project object */; 77 | proxyType = 1; 78 | remoteGlobalIDString = 87FEF3651A9085FA00C60678; 79 | remoteInfo = Bolts; 80 | }; 81 | /* End PBXContainerItemProxy section */ 82 | 83 | /* Begin PBXFileReference section */ 84 | 065894E71C9A933B000FDDA6 /* BoltsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoltsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 065894FF1C9A93B7000FDDA6 /* BoltsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoltsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | 0658951B1C9A947B000FDDA6 /* BoltsSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoltsSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | 81059E4C233EE56E00DE20C1 /* BoltsSwift-Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwift-Shared.xcconfig"; sourceTree = ""; }; 88 | 81059E4D233EE61F00DE20C1 /* BoltsSwiftTests-Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwiftTests-Shared.xcconfig"; sourceTree = ""; }; 89 | 810AB31F1C9B1AC3005B6184 /* XCTestCase+TestName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+TestName.swift"; sourceTree = ""; }; 90 | 812DB5271D3597BF00552C9F /* BoltsSwift-iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwift-iOS.xcconfig"; sourceTree = ""; }; 91 | 812DB5281D3597BF00552C9F /* BoltsSwift-macOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwift-macOS.xcconfig"; sourceTree = ""; }; 92 | 812DB5291D3597BF00552C9F /* BoltsSwift-tvOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwift-tvOS.xcconfig"; sourceTree = ""; }; 93 | 812DB52A1D3597BF00552C9F /* BoltsSwift-watchOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwift-watchOS.xcconfig"; sourceTree = ""; }; 94 | 812DB52B1D3597BF00552C9F /* BoltsSwiftTests-iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwiftTests-iOS.xcconfig"; sourceTree = ""; }; 95 | 812DB52C1D3597BF00552C9F /* BoltsSwiftTests-macOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwiftTests-macOS.xcconfig"; sourceTree = ""; }; 96 | 812DB52D1D3597BF00552C9F /* BoltsSwiftTests-tvOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "BoltsSwiftTests-tvOS.xcconfig"; sourceTree = ""; }; 97 | 812DB52F1D3597BF00552C9F /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; 98 | 812DB5311D3597BF00552C9F /* iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = iOS.xcconfig; sourceTree = ""; }; 99 | 812DB5321D3597BF00552C9F /* macOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = macOS.xcconfig; sourceTree = ""; }; 100 | 812DB5331D3597BF00552C9F /* tvOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = tvOS.xcconfig; sourceTree = ""; }; 101 | 812DB5341D3597BF00552C9F /* watchOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = watchOS.xcconfig; sourceTree = ""; }; 102 | 812DB5361D3597BF00552C9F /* Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Application.xcconfig; sourceTree = ""; }; 103 | 812DB5371D3597BF00552C9F /* DynamicFramework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DynamicFramework.xcconfig; sourceTree = ""; }; 104 | 812DB5381D3597BF00552C9F /* LogicTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = LogicTests.xcconfig; sourceTree = ""; }; 105 | 812DB5391D3597BF00552C9F /* StaticFramework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = StaticFramework.xcconfig; sourceTree = ""; }; 106 | 812DB53B1D3597BF00552C9F /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 107 | 812DB53C1D3597BF00552C9F /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 108 | 812DB53D1D3597BF00552C9F /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 109 | 818DECFF233EED9700EABA07 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; }; 110 | 81951A901D46BA2F00958108 /* Version.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = ""; }; 111 | 81CC14EC1A9BE0A100B28F86 /* BoltsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoltsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | 81CC14F61A9BE0A100B28F86 /* BoltsSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoltsSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 113 | 81D300631C93AF7300E1A1ED /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; 114 | 81D300641C93AF7300E1A1ED /* Executor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Executor.swift; sourceTree = ""; }; 115 | 81D300651C93AF7300E1A1ED /* Task.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; 116 | 81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskCompletionSource.swift; sourceTree = ""; }; 117 | 81D300671C93AF7300E1A1ED /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 118 | 81D300751C93AF9F00E1A1ED /* ExecutorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExecutorTests.swift; sourceTree = ""; }; 119 | 81D300761C93AF9F00E1A1ED /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 120 | 81D300771C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskCompletionSourceTests.swift; sourceTree = ""; }; 121 | 81D300781C93AF9F00E1A1ED /* TaskTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TaskTests.swift; sourceTree = ""; }; 122 | 87FEF3661A9085FA00C60678 /* BoltsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoltsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 123 | 87FEF3711A9085FA00C60678 /* BoltsSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoltsSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 124 | F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+ContinueWith.swift"; sourceTree = ""; }; 125 | F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+Delay.swift"; sourceTree = ""; }; 126 | F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+WhenAll.swift"; sourceTree = ""; }; 127 | F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Task+WhenAny.swift"; sourceTree = ""; }; 128 | /* End PBXFileReference section */ 129 | 130 | /* Begin PBXFrameworksBuildPhase section */ 131 | 065894E31C9A933B000FDDA6 /* Frameworks */ = { 132 | isa = PBXFrameworksBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | 065894F91C9A93B7000FDDA6 /* Frameworks */ = { 139 | isa = PBXFrameworksBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | 065895151C9A947B000FDDA6 /* Frameworks */ = { 146 | isa = PBXFrameworksBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 0658951F1C9A9496000FDDA6 /* BoltsSwift.framework in Frameworks */, 150 | ); 151 | runOnlyForDeploymentPostprocessing = 0; 152 | }; 153 | 81CC14E81A9BE0A100B28F86 /* Frameworks */ = { 154 | isa = PBXFrameworksBuildPhase; 155 | buildActionMask = 2147483647; 156 | files = ( 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | 81CC14F31A9BE0A100B28F86 /* Frameworks */ = { 161 | isa = PBXFrameworksBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | 81CC14F71A9BE0A100B28F86 /* BoltsSwift.framework in Frameworks */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | 87FEF3621A9085FA00C60678 /* Frameworks */ = { 169 | isa = PBXFrameworksBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | 87FEF36E1A9085FA00C60678 /* Frameworks */ = { 176 | isa = PBXFrameworksBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | 87FEF3721A9085FA00C60678 /* BoltsSwift.framework in Frameworks */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXFrameworksBuildPhase section */ 184 | 185 | /* Begin PBXGroup section */ 186 | 812DB5261D3597BF00552C9F /* Configurations */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 81059E4C233EE56E00DE20C1 /* BoltsSwift-Shared.xcconfig */, 190 | 812DB5271D3597BF00552C9F /* BoltsSwift-iOS.xcconfig */, 191 | 812DB5281D3597BF00552C9F /* BoltsSwift-macOS.xcconfig */, 192 | 812DB5291D3597BF00552C9F /* BoltsSwift-tvOS.xcconfig */, 193 | 812DB52A1D3597BF00552C9F /* BoltsSwift-watchOS.xcconfig */, 194 | 81059E4D233EE61F00DE20C1 /* BoltsSwiftTests-Shared.xcconfig */, 195 | 812DB52B1D3597BF00552C9F /* BoltsSwiftTests-iOS.xcconfig */, 196 | 812DB52C1D3597BF00552C9F /* BoltsSwiftTests-macOS.xcconfig */, 197 | 812DB52D1D3597BF00552C9F /* BoltsSwiftTests-tvOS.xcconfig */, 198 | 81951A901D46BA2F00958108 /* Version.xcconfig */, 199 | 812DB52E1D3597BF00552C9F /* Shared */, 200 | ); 201 | path = Configurations; 202 | sourceTree = ""; 203 | }; 204 | 812DB52E1D3597BF00552C9F /* Shared */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 812DB52F1D3597BF00552C9F /* Common.xcconfig */, 208 | 812DB5301D3597BF00552C9F /* Platform */, 209 | 812DB5351D3597BF00552C9F /* Product */, 210 | 812DB53A1D3597BF00552C9F /* Project */, 211 | 812DB53D1D3597BF00552C9F /* Warnings.xcconfig */, 212 | ); 213 | path = Shared; 214 | sourceTree = ""; 215 | }; 216 | 812DB5301D3597BF00552C9F /* Platform */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | 812DB5311D3597BF00552C9F /* iOS.xcconfig */, 220 | 812DB5321D3597BF00552C9F /* macOS.xcconfig */, 221 | 812DB5331D3597BF00552C9F /* tvOS.xcconfig */, 222 | 812DB5341D3597BF00552C9F /* watchOS.xcconfig */, 223 | ); 224 | path = Platform; 225 | sourceTree = ""; 226 | }; 227 | 812DB5351D3597BF00552C9F /* Product */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | 812DB5361D3597BF00552C9F /* Application.xcconfig */, 231 | 812DB5371D3597BF00552C9F /* DynamicFramework.xcconfig */, 232 | 812DB5381D3597BF00552C9F /* LogicTests.xcconfig */, 233 | 812DB5391D3597BF00552C9F /* StaticFramework.xcconfig */, 234 | ); 235 | path = Product; 236 | sourceTree = ""; 237 | }; 238 | 812DB53A1D3597BF00552C9F /* Project */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | 812DB53B1D3597BF00552C9F /* Debug.xcconfig */, 242 | 812DB53C1D3597BF00552C9F /* Release.xcconfig */, 243 | ); 244 | path = Project; 245 | sourceTree = ""; 246 | }; 247 | 81D300611C93AF7300E1A1ED /* Sources */ = { 248 | isa = PBXGroup; 249 | children = ( 250 | 818DECFF233EED9700EABA07 /* Package.swift */, 251 | 81D300621C93AF7300E1A1ED /* BoltsSwift */, 252 | 81D300731C93AF8C00E1A1ED /* Supporting Files */, 253 | ); 254 | path = Sources; 255 | sourceTree = ""; 256 | }; 257 | 81D300621C93AF7300E1A1ED /* BoltsSwift */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | 81D300651C93AF7300E1A1ED /* Task.swift */, 261 | 81D300661C93AF7300E1A1ED /* TaskCompletionSource.swift */, 262 | F569C0C01CFF6A07000749B6 /* Task+ContinueWith.swift */, 263 | F569C0CB1CFF6AEE000749B6 /* Task+Delay.swift */, 264 | F569C0D61CFF6B18000749B6 /* Task+WhenAll.swift */, 265 | F569C0E01CFF6B1F000749B6 /* Task+WhenAny.swift */, 266 | 81D300641C93AF7300E1A1ED /* Executor.swift */, 267 | 81D300631C93AF7300E1A1ED /* Errors.swift */, 268 | ); 269 | path = BoltsSwift; 270 | sourceTree = ""; 271 | }; 272 | 81D300731C93AF8C00E1A1ED /* Supporting Files */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | 81D300671C93AF7300E1A1ED /* Info.plist */, 276 | ); 277 | name = "Supporting Files"; 278 | sourceTree = ""; 279 | }; 280 | 81D300741C93AF9F00E1A1ED /* Tests */ = { 281 | isa = PBXGroup; 282 | children = ( 283 | 81D300781C93AF9F00E1A1ED /* TaskTests.swift */, 284 | 81D300771C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift */, 285 | 81D300751C93AF9F00E1A1ED /* ExecutorTests.swift */, 286 | 810AB31F1C9B1AC3005B6184 /* XCTestCase+TestName.swift */, 287 | 81D300811C93AFA600E1A1ED /* Supporting Files */, 288 | ); 289 | path = Tests; 290 | sourceTree = ""; 291 | }; 292 | 81D300811C93AFA600E1A1ED /* Supporting Files */ = { 293 | isa = PBXGroup; 294 | children = ( 295 | 81D300761C93AF9F00E1A1ED /* Info.plist */, 296 | ); 297 | name = "Supporting Files"; 298 | sourceTree = ""; 299 | }; 300 | 87FEF35C1A9085FA00C60678 = { 301 | isa = PBXGroup; 302 | children = ( 303 | 812DB5261D3597BF00552C9F /* Configurations */, 304 | 81D300611C93AF7300E1A1ED /* Sources */, 305 | 81D300741C93AF9F00E1A1ED /* Tests */, 306 | 87FEF3671A9085FA00C60678 /* Products */, 307 | ); 308 | indentWidth = 4; 309 | sourceTree = ""; 310 | tabWidth = 4; 311 | }; 312 | 87FEF3671A9085FA00C60678 /* Products */ = { 313 | isa = PBXGroup; 314 | children = ( 315 | 87FEF3661A9085FA00C60678 /* BoltsSwift.framework */, 316 | 87FEF3711A9085FA00C60678 /* BoltsSwiftTests.xctest */, 317 | 81CC14EC1A9BE0A100B28F86 /* BoltsSwift.framework */, 318 | 81CC14F61A9BE0A100B28F86 /* BoltsSwiftTests.xctest */, 319 | 065894E71C9A933B000FDDA6 /* BoltsSwift.framework */, 320 | 065894FF1C9A93B7000FDDA6 /* BoltsSwift.framework */, 321 | 0658951B1C9A947B000FDDA6 /* BoltsSwiftTests.xctest */, 322 | ); 323 | name = Products; 324 | sourceTree = ""; 325 | }; 326 | /* End PBXGroup section */ 327 | 328 | /* Begin PBXHeadersBuildPhase section */ 329 | 065894E41C9A933B000FDDA6 /* Headers */ = { 330 | isa = PBXHeadersBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | 065894FA1C9A93B7000FDDA6 /* Headers */ = { 337 | isa = PBXHeadersBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 81CC14E91A9BE0A100B28F86 /* Headers */ = { 344 | isa = PBXHeadersBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | 87FEF3631A9085FA00C60678 /* Headers */ = { 351 | isa = PBXHeadersBuildPhase; 352 | buildActionMask = 2147483647; 353 | files = ( 354 | ); 355 | runOnlyForDeploymentPostprocessing = 0; 356 | }; 357 | /* End PBXHeadersBuildPhase section */ 358 | 359 | /* Begin PBXNativeTarget section */ 360 | 065894E61C9A933B000FDDA6 /* BoltsSwift-watchOS */ = { 361 | isa = PBXNativeTarget; 362 | buildConfigurationList = 065894EE1C9A933B000FDDA6 /* Build configuration list for PBXNativeTarget "BoltsSwift-watchOS" */; 363 | buildPhases = ( 364 | 065894E21C9A933B000FDDA6 /* Sources */, 365 | 065894E31C9A933B000FDDA6 /* Frameworks */, 366 | 065894E41C9A933B000FDDA6 /* Headers */, 367 | 065894E51C9A933B000FDDA6 /* Resources */, 368 | ); 369 | buildRules = ( 370 | ); 371 | dependencies = ( 372 | ); 373 | name = "BoltsSwift-watchOS"; 374 | productName = "BoltsSwift-watchOS"; 375 | productReference = 065894E71C9A933B000FDDA6 /* BoltsSwift.framework */; 376 | productType = "com.apple.product-type.framework"; 377 | }; 378 | 065894F31C9A93B7000FDDA6 /* BoltsSwift-tvOS */ = { 379 | isa = PBXNativeTarget; 380 | buildConfigurationList = 065894FC1C9A93B7000FDDA6 /* Build configuration list for PBXNativeTarget "BoltsSwift-tvOS" */; 381 | buildPhases = ( 382 | 065894F41C9A93B7000FDDA6 /* Sources */, 383 | 065894F91C9A93B7000FDDA6 /* Frameworks */, 384 | 065894FA1C9A93B7000FDDA6 /* Headers */, 385 | 065894FB1C9A93B7000FDDA6 /* Resources */, 386 | ); 387 | buildRules = ( 388 | ); 389 | dependencies = ( 390 | ); 391 | name = "BoltsSwift-tvOS"; 392 | productName = Bolts; 393 | productReference = 065894FF1C9A93B7000FDDA6 /* BoltsSwift.framework */; 394 | productType = "com.apple.product-type.framework"; 395 | }; 396 | 0658950E1C9A947B000FDDA6 /* BoltsSwiftTests-tvOS */ = { 397 | isa = PBXNativeTarget; 398 | buildConfigurationList = 065895181C9A947B000FDDA6 /* Build configuration list for PBXNativeTarget "BoltsSwiftTests-tvOS" */; 399 | buildPhases = ( 400 | 065895111C9A947B000FDDA6 /* Sources */, 401 | 065895151C9A947B000FDDA6 /* Frameworks */, 402 | 065895171C9A947B000FDDA6 /* Resources */, 403 | ); 404 | buildRules = ( 405 | ); 406 | dependencies = ( 407 | 0658951E1C9A948E000FDDA6 /* PBXTargetDependency */, 408 | ); 409 | name = "BoltsSwiftTests-tvOS"; 410 | productName = BoltsTests; 411 | productReference = 0658951B1C9A947B000FDDA6 /* BoltsSwiftTests.xctest */; 412 | productType = "com.apple.product-type.bundle.unit-test"; 413 | }; 414 | 81CC14EB1A9BE0A100B28F86 /* BoltsSwift-macOS */ = { 415 | isa = PBXNativeTarget; 416 | buildConfigurationList = 81CC14FF1A9BE0A100B28F86 /* Build configuration list for PBXNativeTarget "BoltsSwift-macOS" */; 417 | buildPhases = ( 418 | 81CC14E71A9BE0A100B28F86 /* Sources */, 419 | 81CC14E81A9BE0A100B28F86 /* Frameworks */, 420 | 81CC14E91A9BE0A100B28F86 /* Headers */, 421 | 81CC14EA1A9BE0A100B28F86 /* Resources */, 422 | ); 423 | buildRules = ( 424 | ); 425 | dependencies = ( 426 | ); 427 | name = "BoltsSwift-macOS"; 428 | productName = "Bolts-Mac"; 429 | productReference = 81CC14EC1A9BE0A100B28F86 /* BoltsSwift.framework */; 430 | productType = "com.apple.product-type.framework"; 431 | }; 432 | 81CC14F51A9BE0A100B28F86 /* BoltsSwiftTests-macOS */ = { 433 | isa = PBXNativeTarget; 434 | buildConfigurationList = 81CC15021A9BE0A100B28F86 /* Build configuration list for PBXNativeTarget "BoltsSwiftTests-macOS" */; 435 | buildPhases = ( 436 | 81CC14F21A9BE0A100B28F86 /* Sources */, 437 | 81CC14F31A9BE0A100B28F86 /* Frameworks */, 438 | 81CC14F41A9BE0A100B28F86 /* Resources */, 439 | ); 440 | buildRules = ( 441 | ); 442 | dependencies = ( 443 | 81CC14F91A9BE0A100B28F86 /* PBXTargetDependency */, 444 | ); 445 | name = "BoltsSwiftTests-macOS"; 446 | productName = "Bolts-MacTests"; 447 | productReference = 81CC14F61A9BE0A100B28F86 /* BoltsSwiftTests.xctest */; 448 | productType = "com.apple.product-type.bundle.unit-test"; 449 | }; 450 | 87FEF3651A9085FA00C60678 /* BoltsSwift-iOS */ = { 451 | isa = PBXNativeTarget; 452 | buildConfigurationList = 87FEF37C1A9085FA00C60678 /* Build configuration list for PBXNativeTarget "BoltsSwift-iOS" */; 453 | buildPhases = ( 454 | 87FEF3611A9085FA00C60678 /* Sources */, 455 | 87FEF3621A9085FA00C60678 /* Frameworks */, 456 | 87FEF3631A9085FA00C60678 /* Headers */, 457 | 87FEF3641A9085FA00C60678 /* Resources */, 458 | ); 459 | buildRules = ( 460 | ); 461 | dependencies = ( 462 | ); 463 | name = "BoltsSwift-iOS"; 464 | productName = Bolts; 465 | productReference = 87FEF3661A9085FA00C60678 /* BoltsSwift.framework */; 466 | productType = "com.apple.product-type.framework"; 467 | }; 468 | 87FEF3701A9085FA00C60678 /* BoltsSwiftTests-iOS */ = { 469 | isa = PBXNativeTarget; 470 | buildConfigurationList = 87FEF37F1A9085FA00C60678 /* Build configuration list for PBXNativeTarget "BoltsSwiftTests-iOS" */; 471 | buildPhases = ( 472 | 87FEF36D1A9085FA00C60678 /* Sources */, 473 | 87FEF36E1A9085FA00C60678 /* Frameworks */, 474 | 87FEF36F1A9085FA00C60678 /* Resources */, 475 | ); 476 | buildRules = ( 477 | ); 478 | dependencies = ( 479 | 87FEF3741A9085FA00C60678 /* PBXTargetDependency */, 480 | ); 481 | name = "BoltsSwiftTests-iOS"; 482 | productName = BoltsTests; 483 | productReference = 87FEF3711A9085FA00C60678 /* BoltsSwiftTests.xctest */; 484 | productType = "com.apple.product-type.bundle.unit-test"; 485 | }; 486 | /* End PBXNativeTarget section */ 487 | 488 | /* Begin PBXProject section */ 489 | 87FEF35D1A9085FA00C60678 /* Project object */ = { 490 | isa = PBXProject; 491 | attributes = { 492 | LastSwiftMigration = 0700; 493 | LastSwiftUpdateCheck = 0700; 494 | LastUpgradeCheck = 1100; 495 | ORGANIZATIONNAME = Facebook; 496 | TargetAttributes = { 497 | 065894E61C9A933B000FDDA6 = { 498 | CreatedOnToolsVersion = 7.2.1; 499 | }; 500 | 81CC14EB1A9BE0A100B28F86 = { 501 | CreatedOnToolsVersion = 6.3; 502 | }; 503 | 81CC14F51A9BE0A100B28F86 = { 504 | CreatedOnToolsVersion = 6.3; 505 | }; 506 | 87FEF3651A9085FA00C60678 = { 507 | CreatedOnToolsVersion = 6.3; 508 | LastSwiftMigration = 1100; 509 | }; 510 | 87FEF3701A9085FA00C60678 = { 511 | CreatedOnToolsVersion = 6.3; 512 | LastSwiftMigration = 1100; 513 | }; 514 | }; 515 | }; 516 | buildConfigurationList = 87FEF3601A9085FA00C60678 /* Build configuration list for PBXProject "BoltsSwift" */; 517 | compatibilityVersion = "Xcode 3.2"; 518 | developmentRegion = English; 519 | hasScannedForEncodings = 0; 520 | knownRegions = ( 521 | English, 522 | Base, 523 | ); 524 | mainGroup = 87FEF35C1A9085FA00C60678; 525 | productRefGroup = 87FEF3671A9085FA00C60678 /* Products */; 526 | projectDirPath = ""; 527 | projectRoot = ""; 528 | targets = ( 529 | 87FEF3651A9085FA00C60678 /* BoltsSwift-iOS */, 530 | 87FEF3701A9085FA00C60678 /* BoltsSwiftTests-iOS */, 531 | 81CC14EB1A9BE0A100B28F86 /* BoltsSwift-macOS */, 532 | 81CC14F51A9BE0A100B28F86 /* BoltsSwiftTests-macOS */, 533 | 065894F31C9A93B7000FDDA6 /* BoltsSwift-tvOS */, 534 | 0658950E1C9A947B000FDDA6 /* BoltsSwiftTests-tvOS */, 535 | 065894E61C9A933B000FDDA6 /* BoltsSwift-watchOS */, 536 | ); 537 | }; 538 | /* End PBXProject section */ 539 | 540 | /* Begin PBXResourcesBuildPhase section */ 541 | 065894E51C9A933B000FDDA6 /* Resources */ = { 542 | isa = PBXResourcesBuildPhase; 543 | buildActionMask = 2147483647; 544 | files = ( 545 | ); 546 | runOnlyForDeploymentPostprocessing = 0; 547 | }; 548 | 065894FB1C9A93B7000FDDA6 /* Resources */ = { 549 | isa = PBXResourcesBuildPhase; 550 | buildActionMask = 2147483647; 551 | files = ( 552 | ); 553 | runOnlyForDeploymentPostprocessing = 0; 554 | }; 555 | 065895171C9A947B000FDDA6 /* Resources */ = { 556 | isa = PBXResourcesBuildPhase; 557 | buildActionMask = 2147483647; 558 | files = ( 559 | ); 560 | runOnlyForDeploymentPostprocessing = 0; 561 | }; 562 | 81CC14EA1A9BE0A100B28F86 /* Resources */ = { 563 | isa = PBXResourcesBuildPhase; 564 | buildActionMask = 2147483647; 565 | files = ( 566 | ); 567 | runOnlyForDeploymentPostprocessing = 0; 568 | }; 569 | 81CC14F41A9BE0A100B28F86 /* Resources */ = { 570 | isa = PBXResourcesBuildPhase; 571 | buildActionMask = 2147483647; 572 | files = ( 573 | ); 574 | runOnlyForDeploymentPostprocessing = 0; 575 | }; 576 | 87FEF3641A9085FA00C60678 /* Resources */ = { 577 | isa = PBXResourcesBuildPhase; 578 | buildActionMask = 2147483647; 579 | files = ( 580 | ); 581 | runOnlyForDeploymentPostprocessing = 0; 582 | }; 583 | 87FEF36F1A9085FA00C60678 /* Resources */ = { 584 | isa = PBXResourcesBuildPhase; 585 | buildActionMask = 2147483647; 586 | files = ( 587 | ); 588 | runOnlyForDeploymentPostprocessing = 0; 589 | }; 590 | /* End PBXResourcesBuildPhase section */ 591 | 592 | /* Begin PBXSourcesBuildPhase section */ 593 | 065894E21C9A933B000FDDA6 /* Sources */ = { 594 | isa = PBXSourcesBuildPhase; 595 | buildActionMask = 2147483647; 596 | files = ( 597 | 065894F21C9A9391000FDDA6 /* Errors.swift in Sources */, 598 | F569C0DA1CFF6B18000749B6 /* Task+WhenAll.swift in Sources */, 599 | 065894EF1C9A9391000FDDA6 /* Task.swift in Sources */, 600 | F569C0CF1CFF6AEE000749B6 /* Task+Delay.swift in Sources */, 601 | F569C0C41CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */, 602 | F569C0E41CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */, 603 | 065894F11C9A9391000FDDA6 /* Executor.swift in Sources */, 604 | 065894F01C9A9391000FDDA6 /* TaskCompletionSource.swift in Sources */, 605 | ); 606 | runOnlyForDeploymentPostprocessing = 0; 607 | }; 608 | 065894F41C9A93B7000FDDA6 /* Sources */ = { 609 | isa = PBXSourcesBuildPhase; 610 | buildActionMask = 2147483647; 611 | files = ( 612 | 065894F51C9A93B7000FDDA6 /* Executor.swift in Sources */, 613 | F569C0D91CFF6B18000749B6 /* Task+WhenAll.swift in Sources */, 614 | 065894F61C9A93B7000FDDA6 /* Task.swift in Sources */, 615 | F569C0CE1CFF6AEE000749B6 /* Task+Delay.swift in Sources */, 616 | F569C0C31CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */, 617 | F569C0E31CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */, 618 | 065894F71C9A93B7000FDDA6 /* Errors.swift in Sources */, 619 | 065894F81C9A93B7000FDDA6 /* TaskCompletionSource.swift in Sources */, 620 | ); 621 | runOnlyForDeploymentPostprocessing = 0; 622 | }; 623 | 065895111C9A947B000FDDA6 /* Sources */ = { 624 | isa = PBXSourcesBuildPhase; 625 | buildActionMask = 2147483647; 626 | files = ( 627 | 065895121C9A947B000FDDA6 /* ExecutorTests.swift in Sources */, 628 | 065895131C9A947B000FDDA6 /* TaskTests.swift in Sources */, 629 | 065895141C9A947B000FDDA6 /* TaskCompletionSourceTests.swift in Sources */, 630 | 810AB3221C9B1AC3005B6184 /* XCTestCase+TestName.swift in Sources */, 631 | ); 632 | runOnlyForDeploymentPostprocessing = 0; 633 | }; 634 | 81CC14E71A9BE0A100B28F86 /* Sources */ = { 635 | isa = PBXSourcesBuildPhase; 636 | buildActionMask = 2147483647; 637 | files = ( 638 | 81D3006B1C93AF7300E1A1ED /* Executor.swift in Sources */, 639 | F569C0D81CFF6B18000749B6 /* Task+WhenAll.swift in Sources */, 640 | 81D3006D1C93AF7300E1A1ED /* Task.swift in Sources */, 641 | F569C0CD1CFF6AEE000749B6 /* Task+Delay.swift in Sources */, 642 | F569C0C21CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */, 643 | F569C0E21CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */, 644 | 81D300691C93AF7300E1A1ED /* Errors.swift in Sources */, 645 | 81D3006F1C93AF7300E1A1ED /* TaskCompletionSource.swift in Sources */, 646 | ); 647 | runOnlyForDeploymentPostprocessing = 0; 648 | }; 649 | 81CC14F21A9BE0A100B28F86 /* Sources */ = { 650 | isa = PBXSourcesBuildPhase; 651 | buildActionMask = 2147483647; 652 | files = ( 653 | 81D3007A1C93AF9F00E1A1ED /* ExecutorTests.swift in Sources */, 654 | 81D300801C93AF9F00E1A1ED /* TaskTests.swift in Sources */, 655 | 81D3007E1C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift in Sources */, 656 | 810AB3211C9B1AC3005B6184 /* XCTestCase+TestName.swift in Sources */, 657 | ); 658 | runOnlyForDeploymentPostprocessing = 0; 659 | }; 660 | 87FEF3611A9085FA00C60678 /* Sources */ = { 661 | isa = PBXSourcesBuildPhase; 662 | buildActionMask = 2147483647; 663 | files = ( 664 | 81D3006A1C93AF7300E1A1ED /* Executor.swift in Sources */, 665 | F569C0D71CFF6B18000749B6 /* Task+WhenAll.swift in Sources */, 666 | 81D3006C1C93AF7300E1A1ED /* Task.swift in Sources */, 667 | F569C0CC1CFF6AEE000749B6 /* Task+Delay.swift in Sources */, 668 | F569C0C11CFF6A07000749B6 /* Task+ContinueWith.swift in Sources */, 669 | F569C0E11CFF6B1F000749B6 /* Task+WhenAny.swift in Sources */, 670 | 81D300681C93AF7300E1A1ED /* Errors.swift in Sources */, 671 | 81D3006E1C93AF7300E1A1ED /* TaskCompletionSource.swift in Sources */, 672 | ); 673 | runOnlyForDeploymentPostprocessing = 0; 674 | }; 675 | 87FEF36D1A9085FA00C60678 /* Sources */ = { 676 | isa = PBXSourcesBuildPhase; 677 | buildActionMask = 2147483647; 678 | files = ( 679 | 81D300791C93AF9F00E1A1ED /* ExecutorTests.swift in Sources */, 680 | 81D3007F1C93AF9F00E1A1ED /* TaskTests.swift in Sources */, 681 | 81D3007D1C93AF9F00E1A1ED /* TaskCompletionSourceTests.swift in Sources */, 682 | 810AB3201C9B1AC3005B6184 /* XCTestCase+TestName.swift in Sources */, 683 | ); 684 | runOnlyForDeploymentPostprocessing = 0; 685 | }; 686 | /* End PBXSourcesBuildPhase section */ 687 | 688 | /* Begin PBXTargetDependency section */ 689 | 0658951E1C9A948E000FDDA6 /* PBXTargetDependency */ = { 690 | isa = PBXTargetDependency; 691 | target = 065894F31C9A93B7000FDDA6 /* BoltsSwift-tvOS */; 692 | targetProxy = 0658951D1C9A948E000FDDA6 /* PBXContainerItemProxy */; 693 | }; 694 | 81CC14F91A9BE0A100B28F86 /* PBXTargetDependency */ = { 695 | isa = PBXTargetDependency; 696 | target = 81CC14EB1A9BE0A100B28F86 /* BoltsSwift-macOS */; 697 | targetProxy = 81CC14F81A9BE0A100B28F86 /* PBXContainerItemProxy */; 698 | }; 699 | 87FEF3741A9085FA00C60678 /* PBXTargetDependency */ = { 700 | isa = PBXTargetDependency; 701 | target = 87FEF3651A9085FA00C60678 /* BoltsSwift-iOS */; 702 | targetProxy = 87FEF3731A9085FA00C60678 /* PBXContainerItemProxy */; 703 | }; 704 | /* End PBXTargetDependency section */ 705 | 706 | /* Begin XCBuildConfiguration section */ 707 | 065894EC1C9A933B000FDDA6 /* Debug */ = { 708 | isa = XCBuildConfiguration; 709 | baseConfigurationReference = 812DB52A1D3597BF00552C9F /* BoltsSwift-watchOS.xcconfig */; 710 | buildSettings = { 711 | }; 712 | name = Debug; 713 | }; 714 | 065894ED1C9A933B000FDDA6 /* Release */ = { 715 | isa = XCBuildConfiguration; 716 | baseConfigurationReference = 812DB52A1D3597BF00552C9F /* BoltsSwift-watchOS.xcconfig */; 717 | buildSettings = { 718 | }; 719 | name = Release; 720 | }; 721 | 065894FD1C9A93B7000FDDA6 /* Debug */ = { 722 | isa = XCBuildConfiguration; 723 | baseConfigurationReference = 812DB5291D3597BF00552C9F /* BoltsSwift-tvOS.xcconfig */; 724 | buildSettings = { 725 | }; 726 | name = Debug; 727 | }; 728 | 065894FE1C9A93B7000FDDA6 /* Release */ = { 729 | isa = XCBuildConfiguration; 730 | baseConfigurationReference = 812DB5291D3597BF00552C9F /* BoltsSwift-tvOS.xcconfig */; 731 | buildSettings = { 732 | }; 733 | name = Release; 734 | }; 735 | 065895191C9A947B000FDDA6 /* Debug */ = { 736 | isa = XCBuildConfiguration; 737 | baseConfigurationReference = 812DB52D1D3597BF00552C9F /* BoltsSwiftTests-tvOS.xcconfig */; 738 | buildSettings = { 739 | }; 740 | name = Debug; 741 | }; 742 | 0658951A1C9A947B000FDDA6 /* Release */ = { 743 | isa = XCBuildConfiguration; 744 | baseConfigurationReference = 812DB52D1D3597BF00552C9F /* BoltsSwiftTests-tvOS.xcconfig */; 745 | buildSettings = { 746 | }; 747 | name = Release; 748 | }; 749 | 81CC15001A9BE0A100B28F86 /* Debug */ = { 750 | isa = XCBuildConfiguration; 751 | baseConfigurationReference = 812DB5281D3597BF00552C9F /* BoltsSwift-macOS.xcconfig */; 752 | buildSettings = { 753 | }; 754 | name = Debug; 755 | }; 756 | 81CC15011A9BE0A100B28F86 /* Release */ = { 757 | isa = XCBuildConfiguration; 758 | baseConfigurationReference = 812DB5281D3597BF00552C9F /* BoltsSwift-macOS.xcconfig */; 759 | buildSettings = { 760 | }; 761 | name = Release; 762 | }; 763 | 81CC15031A9BE0A100B28F86 /* Debug */ = { 764 | isa = XCBuildConfiguration; 765 | baseConfigurationReference = 812DB52C1D3597BF00552C9F /* BoltsSwiftTests-macOS.xcconfig */; 766 | buildSettings = { 767 | }; 768 | name = Debug; 769 | }; 770 | 81CC15041A9BE0A100B28F86 /* Release */ = { 771 | isa = XCBuildConfiguration; 772 | baseConfigurationReference = 812DB52C1D3597BF00552C9F /* BoltsSwiftTests-macOS.xcconfig */; 773 | buildSettings = { 774 | }; 775 | name = Release; 776 | }; 777 | 87FEF37A1A9085FA00C60678 /* Debug */ = { 778 | isa = XCBuildConfiguration; 779 | baseConfigurationReference = 812DB53B1D3597BF00552C9F /* Debug.xcconfig */; 780 | buildSettings = { 781 | }; 782 | name = Debug; 783 | }; 784 | 87FEF37B1A9085FA00C60678 /* Release */ = { 785 | isa = XCBuildConfiguration; 786 | baseConfigurationReference = 812DB53C1D3597BF00552C9F /* Release.xcconfig */; 787 | buildSettings = { 788 | }; 789 | name = Release; 790 | }; 791 | 87FEF37D1A9085FA00C60678 /* Debug */ = { 792 | isa = XCBuildConfiguration; 793 | baseConfigurationReference = 812DB5271D3597BF00552C9F /* BoltsSwift-iOS.xcconfig */; 794 | buildSettings = { 795 | }; 796 | name = Debug; 797 | }; 798 | 87FEF37E1A9085FA00C60678 /* Release */ = { 799 | isa = XCBuildConfiguration; 800 | baseConfigurationReference = 812DB5271D3597BF00552C9F /* BoltsSwift-iOS.xcconfig */; 801 | buildSettings = { 802 | }; 803 | name = Release; 804 | }; 805 | 87FEF3801A9085FA00C60678 /* Debug */ = { 806 | isa = XCBuildConfiguration; 807 | baseConfigurationReference = 812DB52B1D3597BF00552C9F /* BoltsSwiftTests-iOS.xcconfig */; 808 | buildSettings = { 809 | }; 810 | name = Debug; 811 | }; 812 | 87FEF3811A9085FA00C60678 /* Release */ = { 813 | isa = XCBuildConfiguration; 814 | baseConfigurationReference = 812DB52B1D3597BF00552C9F /* BoltsSwiftTests-iOS.xcconfig */; 815 | buildSettings = { 816 | }; 817 | name = Release; 818 | }; 819 | /* End XCBuildConfiguration section */ 820 | 821 | /* Begin XCConfigurationList section */ 822 | 065894EE1C9A933B000FDDA6 /* Build configuration list for PBXNativeTarget "BoltsSwift-watchOS" */ = { 823 | isa = XCConfigurationList; 824 | buildConfigurations = ( 825 | 065894EC1C9A933B000FDDA6 /* Debug */, 826 | 065894ED1C9A933B000FDDA6 /* Release */, 827 | ); 828 | defaultConfigurationIsVisible = 0; 829 | defaultConfigurationName = Release; 830 | }; 831 | 065894FC1C9A93B7000FDDA6 /* Build configuration list for PBXNativeTarget "BoltsSwift-tvOS" */ = { 832 | isa = XCConfigurationList; 833 | buildConfigurations = ( 834 | 065894FD1C9A93B7000FDDA6 /* Debug */, 835 | 065894FE1C9A93B7000FDDA6 /* Release */, 836 | ); 837 | defaultConfigurationIsVisible = 0; 838 | defaultConfigurationName = Release; 839 | }; 840 | 065895181C9A947B000FDDA6 /* Build configuration list for PBXNativeTarget "BoltsSwiftTests-tvOS" */ = { 841 | isa = XCConfigurationList; 842 | buildConfigurations = ( 843 | 065895191C9A947B000FDDA6 /* Debug */, 844 | 0658951A1C9A947B000FDDA6 /* Release */, 845 | ); 846 | defaultConfigurationIsVisible = 0; 847 | defaultConfigurationName = Release; 848 | }; 849 | 81CC14FF1A9BE0A100B28F86 /* Build configuration list for PBXNativeTarget "BoltsSwift-macOS" */ = { 850 | isa = XCConfigurationList; 851 | buildConfigurations = ( 852 | 81CC15001A9BE0A100B28F86 /* Debug */, 853 | 81CC15011A9BE0A100B28F86 /* Release */, 854 | ); 855 | defaultConfigurationIsVisible = 0; 856 | defaultConfigurationName = Release; 857 | }; 858 | 81CC15021A9BE0A100B28F86 /* Build configuration list for PBXNativeTarget "BoltsSwiftTests-macOS" */ = { 859 | isa = XCConfigurationList; 860 | buildConfigurations = ( 861 | 81CC15031A9BE0A100B28F86 /* Debug */, 862 | 81CC15041A9BE0A100B28F86 /* Release */, 863 | ); 864 | defaultConfigurationIsVisible = 0; 865 | defaultConfigurationName = Release; 866 | }; 867 | 87FEF3601A9085FA00C60678 /* Build configuration list for PBXProject "BoltsSwift" */ = { 868 | isa = XCConfigurationList; 869 | buildConfigurations = ( 870 | 87FEF37A1A9085FA00C60678 /* Debug */, 871 | 87FEF37B1A9085FA00C60678 /* Release */, 872 | ); 873 | defaultConfigurationIsVisible = 0; 874 | defaultConfigurationName = Release; 875 | }; 876 | 87FEF37C1A9085FA00C60678 /* Build configuration list for PBXNativeTarget "BoltsSwift-iOS" */ = { 877 | isa = XCConfigurationList; 878 | buildConfigurations = ( 879 | 87FEF37D1A9085FA00C60678 /* Debug */, 880 | 87FEF37E1A9085FA00C60678 /* Release */, 881 | ); 882 | defaultConfigurationIsVisible = 0; 883 | defaultConfigurationName = Release; 884 | }; 885 | 87FEF37F1A9085FA00C60678 /* Build configuration list for PBXNativeTarget "BoltsSwiftTests-iOS" */ = { 886 | isa = XCConfigurationList; 887 | buildConfigurations = ( 888 | 87FEF3801A9085FA00C60678 /* Debug */, 889 | 87FEF3811A9085FA00C60678 /* Release */, 890 | ); 891 | defaultConfigurationIsVisible = 0; 892 | defaultConfigurationName = Release; 893 | }; 894 | /* End XCConfigurationList section */ 895 | }; 896 | rootObject = 87FEF35D1A9085FA00C60678 /* Project object */; 897 | } 898 | --------------------------------------------------------------------------------