├── Assets ├── logo.png └── logo.sketch ├── Package.swift ├── docs.sh ├── .gitignore ├── Eventually.xcworkspace └── contents.xcworkspacedata ├── Playground.playground ├── contents.xcplayground └── Pages │ ├── Errors.xcplaygroundpage │ └── Contents.swift │ ├── Execution Contexts.xcplaygroundpage │ └── Contents.swift │ └── Basics.xcplaygroundpage │ └── Contents.swift ├── Sources ├── Observable.swift ├── Resolve.swift ├── FutureResult.swift ├── Mutex.swift ├── ExecutionContext.swift ├── Future+Operations.swift └── Future.swift ├── Eventually.podspec ├── Configs ├── EventuallyTests.plist └── Eventually.plist ├── LICENSE ├── Eventually.xcodeproj ├── xcshareddata │ └── xcschemes │ │ ├── Eventually-watchOS.xcscheme │ │ ├── Eventually-tvOS.xcscheme │ │ ├── Eventually-macOS.xcscheme │ │ └── Eventually-iOS.xcscheme └── project.pbxproj ├── README.md └── Tests └── EventuallyTests.swift /Assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrkno/Eventually/HEAD/Assets/logo.png -------------------------------------------------------------------------------- /Assets/logo.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrkno/Eventually/HEAD/Assets/logo.sketch -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "Eventually" 5 | ) 6 | -------------------------------------------------------------------------------- /docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | jazzy \ 4 | --theme fullwidth \ 5 | --author NRK \ 6 | --author_url https://nrkno.github.io \ 7 | --github_url https://github.com/nrkno/Eventually \ 8 | --github-file-prefix https://github.com/nrkno/Eventually/tree/master 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # xcode noise 2 | build/* 3 | dist/* 4 | *.pbxuser 5 | *.mode1v3 6 | *.mode2v3 7 | *.perspectivev3 8 | *.moved-aside 9 | 10 | # osx noise 11 | .DS_Store 12 | profile 13 | 14 | *.xcodeproj/project.xcworkspace/* 15 | */xcuserdata/* 16 | 17 | docs/* 18 | 19 | *.playground/*.o 20 | -------------------------------------------------------------------------------- /Eventually.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Playground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/Observable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observable.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 21/02/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | internal final class Observable { 12 | let context: ExecutionContext 13 | private let observer: (FutureResult) -> Void 14 | 15 | init(context: ExecutionContext, observer: @escaping (FutureResult) -> Void) { 16 | self.context = context 17 | self.observer = observer 18 | } 19 | 20 | func call(result: FutureResult) { 21 | context.apply { 22 | self.observer(result) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Resolve.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Resolve.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 01/03/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Used to resolve a future, giving it either a success or a failure value. 12 | /// Note: mostly exist to give a slightly more fluid api when resolving a future 13 | public struct Resolve { 14 | internal let closure: ((FutureResult) -> Void) 15 | 16 | /// Resolves with a successful value 17 | public func success(_ value: T) { 18 | closure(.success(value)) 19 | } 20 | 21 | // Resolves with an error 22 | public func failure(_ error: Error) { 23 | closure(.failure(error)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Eventually.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Eventually" 3 | s.version = "0.4" 4 | s.summary = "SWift Future/Promise library" 5 | s.description = <<-DESC 6 | A Swift Future/Promise library that can be used to model and transform asynchronous results 7 | DESC 8 | s.homepage = "https://github.com/nrkno/Eventually" 9 | s.license = { :type => "MIT", :file => "LICENSE" } 10 | s.author = { "Johan Sørensen" => "johan.sorensen@nrk.no" } 11 | s.ios.deployment_target = "9.0" 12 | s.osx.deployment_target = "10.10" 13 | s.watchos.deployment_target = "3.0" 14 | s.tvos.deployment_target = "9.0" 15 | s.source = { :git => "https://github.com/nrkno/Eventually.git", :tag => s.version.to_s } 16 | s.source_files = "Sources/**/*" 17 | s.frameworks = "Foundation" 18 | end 19 | -------------------------------------------------------------------------------- /Configs/EventuallyTests.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 | -------------------------------------------------------------------------------- /Playground.playground/Pages/Errors.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Eventually 3 | import XCPlayground 4 | XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 5 | 6 | //: ## Error handling 7 | 8 | enum Trouble: Error { 9 | case fail 10 | } 11 | 12 | let failingFuture = Future { resolve in 13 | resolve.failure(Trouble.fail) 14 | } 15 | 16 | //: Switching on the Result type 17 | 18 | failingFuture.then { result in 19 | switch result { 20 | case .success(let value): 21 | print("failingFuture is", value) 22 | case .failure(let error): 23 | print("failingFuture failed: ", error) 24 | } 25 | } 26 | 27 | //: The success() + failure() helpers 28 | 29 | failingFuture.map { value in 30 | return "the value is \(value)" 31 | }.success { value in 32 | print(value) 33 | }.failure { error in 34 | print("Error: ", error) 35 | } 36 | 37 | 38 | //: [Previous: Basics](@previous) | [Previous: Execution Contexts](@next) 39 | -------------------------------------------------------------------------------- /Configs/Eventually.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 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2017 NRK. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Sources/FutureResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FutureResult.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 21/02/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Represents a Future result that can have only one of two states: .success (the value) or .failure (an error) 12 | public enum FutureResult { 13 | case success(T) 14 | case failure(Error) 15 | 16 | /// The value in case of .success 17 | public var value: T? { 18 | return map({ $0 }) 19 | } 20 | 21 | /// The error in case of .failure 22 | public var error: Error? { 23 | if case .failure(let error) = self { 24 | return error 25 | } 26 | return nil 27 | } 28 | 29 | /// If self is .success then the transform closure is run on the result, otherwise nil is returned 30 | public func map(_ transform: (T) -> T) -> T? { 31 | switch self { 32 | case .success(let value): 33 | return transform(value) 34 | case .failure: 35 | return nil 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 NRK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Playground.playground/Pages/Execution Contexts.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Eventually 3 | import XCPlayground 4 | XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 5 | 6 | /*: 7 | ## Execution Contexts 8 | 9 | Most of the methods takes an optional `on:` parameter that dictates on which ExecutionContext 10 | The task should be performed on, the ExecutionContext is a shorthand way of specifying the queue 11 | */ 12 | 13 | //:First, create a Future that runs its resolve closure on a background queue 14 | let backgroundFuture = Future(on: .background) { resolve in 15 | // runs on background queue 16 | resolve.success(42) 17 | } 18 | 19 | //: Then we transform (map) the value of the future, once it has a value, on our own queue 20 | let queue = DispatchQueue(label: "no.nrk.Eventually.playground") 21 | let mapped = backgroundFuture.map(on: .queue(queue)) { value in 22 | // Runs on our own queue 23 | return value * Double.pi 24 | } 25 | 26 | //: Then we get notified on the main thread (the default) if the future resolves with a successful value 27 | mapped.success(on: .main) { value in 28 | print("back on main thread the value is", value) 29 | } 30 | 31 | //: [Previous: Errors](@previous) 32 | -------------------------------------------------------------------------------- /Sources/Mutex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mutex.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 21/02/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | #if os(Linux) 10 | import Glibc 11 | #else 12 | import Darwin 13 | #endif 14 | 15 | internal final class Mutex { 16 | private var mutex = pthread_mutex_t() 17 | 18 | init(){ 19 | let res = pthread_mutex_init(&mutex, nil) 20 | if res != 0 { 21 | fatalError("failed to init mutex: \(strerror(res))") 22 | } 23 | } 24 | 25 | deinit { 26 | let res = pthread_mutex_destroy(&mutex) 27 | if res != 0 { 28 | print("failed to destroy mutex: \(strerror(res))") 29 | } 30 | } 31 | 32 | func lock() { 33 | try! aquire(pthread_mutex_lock(&mutex)) 34 | } 35 | 36 | func unlock() { 37 | try! aquire(pthread_mutex_unlock(&mutex)) 38 | } 39 | 40 | @discardableResult 41 | func locked(_ task: () -> T) -> T { 42 | lock() 43 | defer { unlock() } 44 | return task() 45 | } 46 | 47 | private struct MutexError: Error { 48 | let message: String 49 | } 50 | 51 | private func aquire(_ item: @autoclosure () -> Int32) throws { 52 | let res = item() 53 | if res != 0 { 54 | throw MutexError(message: "\(strerror(res))") 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/ExecutionContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExecutionContext.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 21/02/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Dispatch 11 | 12 | /// The GCD queue context in which a given Future operation should be performed 13 | public enum ExecutionContext { 14 | /// The main queue, if already on the main queue the task is run immediately 15 | case main 16 | /// The background QoS queue 17 | case background 18 | /// A global queue with the given QoSClass 19 | case global(DispatchQoS.QoSClass) 20 | /// A queue of your choice 21 | case queue(DispatchQueue) 22 | 23 | internal var queue: DispatchQueue { 24 | switch self { 25 | case .main: 26 | return DispatchQueue.main 27 | case .background: 28 | return DispatchQueue.global(qos: .background) 29 | case .global(let qos): 30 | return DispatchQueue.global(qos: qos) 31 | case .queue(let queue): 32 | return queue 33 | } 34 | } 35 | 36 | internal func apply(execute: @escaping () -> Void) { 37 | switch (self, Thread.isMainThread) { 38 | case (.main, true): 39 | execute() 40 | default: 41 | queue.async { 42 | execute() 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Playground.playground/Pages/Basics.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Eventually 3 | import XCPlayground 4 | XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 5 | 6 | /*: 7 | # Eventually 8 | 9 | In order for this playground to work, make sure that you've opened the Eventually.xcworkspace workspace and then selected the playgound. Then build the Eventually-iOS scheme. 10 | 11 | ## Basics 12 | 13 | ### Basic usage & the Result type 14 | */ 15 | 16 | /*: A Future represents a value that has not yet materialized, once it is ready we'll call the `resolve` closure with either a `.success` or `.falure` depending on whether the Future resolves to some value or if it encountered an error along the way 17 | */ 18 | let basicFuture = Future(resolver: { resolve in 19 | resolve.success(42) 20 | }) 21 | 22 | /*: At this point the future may or may not hold a value, so we can use `then()` to get notified when it resolves/materializes. We get delivered a Result enum type, which can hold either a `.success` or `.failure` 23 | */ 24 | basicFuture.then { result in 25 | switch result { 26 | case .success(let value): 27 | print("basicFuture is", value) 28 | case .failure(let error): 29 | print("basicFuture failed: ", error) 30 | } 31 | } 32 | 33 | //: ### Wrapping existing API 34 | 35 | //: Do something expensive on a background queue, then bounce back to main 36 | func advancedMathematics(base: Int, completion: @escaping (Int) -> Void) { 37 | DispatchQueue.global(qos: .background).async { 38 | let result = base * 2 39 | DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { 40 | completion(result) 41 | } 42 | } 43 | } 44 | advancedMathematics(base: 42) { value in 45 | // value is 84 46 | } 47 | 48 | //: Existing APIs can easily be wrapped to provide a Future simply by calling the resolve handler once the operation finishes 49 | func futureMathematics(base: Int) -> Future { 50 | return Future { resolve in 51 | advancedMathematics(base: base, completion: { value in 52 | resolve.success(value) 53 | }) 54 | } 55 | } 56 | 57 | let asyncFuture = futureMathematics(base: 42) 58 | //: `success()` and `failure()` are provided as chainable shorthand methods 59 | asyncFuture.success { value in 60 | print("ayncFuture is ", value) 61 | } 62 | 63 | //: ### Transforming Futures 64 | 65 | //: The (successful) result of a Future can be mapped into another value. The transform only occurs when the Future value has materialized. Multiple `map()`s (and any other Future method) can be chained 66 | asyncFuture 67 | .map({ $0 / 2}) 68 | .map({ n in 69 | return "The meaning is \(n)" 70 | }) 71 | .success { value in 72 | print("transformed future is ", value) 73 | } 74 | 75 | //: ### Alternative API 76 | 77 | //: If it suits you implementation better you can use a non-closure based API to resolve Futures 78 | 79 | let future = Future() 80 | future.success { value in 81 | print(value) 82 | } 83 | future.resolve(success: 42) 84 | 85 | 86 | //: [Next: Errors](@next) 87 | -------------------------------------------------------------------------------- /Eventually.xcodeproj/xcshareddata/xcschemes/Eventually-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Eventually logo](/Assets/logo.png) 2 | 3 | # Eventually 4 | 5 | A Swift implementation of a [Future](https://en.wikipedia.org/wiki/Futures_and_promises), which can be used to model and transform asynchronous results while making it easy to bounce results between dispatch queues 6 | 7 | ## Usage 8 | 9 | Futures in Eventually can be used to wrap existing APIs, or to create new APIs using Futures 10 | 11 | ```Swift 12 | func operation(completion: (Int) -> Void) { 13 | DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { 14 | completion(42) 15 | } 16 | } 17 | 18 | Future { resolve in 19 | operation { value 20 | resolve.success(value) 21 | } 22 | }.then { result in 23 | switch result { 24 | case .success(let value): 25 | print("value is", value) // "value is 42" 26 | case .failure(let error): 27 | print("something went wrong:", error) 28 | } 29 | } 30 | ``` 31 | 32 | When initializing a Future the closure receives a "resolver", this resolver is simply a closure that you will call with a [FutureResult](/Sources/FutureResult.swift), a Result enum type which can be either `.success` or `.failure`. 33 | 34 | There's also a couple of short-hand methods available 35 | 36 | ```swift 37 | func calculateAge() -> Future { 38 | // ... 39 | } 40 | calculateAge().success { (value: Int) in 41 | print("Success value from calling calculateAge() is", value) 42 | }.failure { error in 43 | print(The Future returned by calculateAge() gave us an error:", error) 44 | } 45 | ``` 46 | 47 | A non-closure based API for resolving futures is also available 48 | 49 | ```swift 50 | let future = Future() 51 | future.success { value in 52 | ... 53 | } 54 | future.resolve(success: age) 55 | ``` 56 | 57 | ### Mapping values 58 | 59 | With Eventually it is possible to `map()` one Future type to another, allowing us to compose and transform things easily 60 | 61 | ```swift 62 | calculateAge().map({ (value: Int) -> String in 63 | return "Age is \(age)" 64 | }).success { value in 65 | print(value) // "Age is 42" 66 | } 67 | ``` 68 | 69 | Like always, chaining is possible so multiple transforms can be done 70 | 71 | ### Evaluation Contexts 72 | 73 | Most of the methods operating on a Future accepts an [EvaluationContext](/Sources/EvaluationContext.swift) that describes what GCD queue the operation should be called on 74 | 75 | ```swift 76 | Future(on: .background) { resolve 77 | // Performed on a background queue (eg `DispatchQueue.global(qos: .background)`) 78 | resolve.success("hello")) 79 | }.map(on: .queue(someCustomQueue)) { value in 80 | // will be called on the supplied DispatchQueue (`someCustomQueue`) 81 | return value + " world" 82 | }.map(on: .main) { value in 83 | // Mapping occurs on the main thread 84 | let label = UILabel() 85 | label.text = value 86 | return text 87 | }.success { label in 88 | // default is the `.main` context 89 | self.view.addSubview(label) 90 | } 91 | ``` 92 | 93 | ## Installation 94 | 95 | Eventually is available as a CocoaPod (`pod 'Eventually'`) and the Swift Package Manager. Framework installation is also available by dragging the Eventually.xcodeproj into your project or via Carthage. 96 | 97 | Eventually has no dependencies outside of Foundation and Dispatch (GCD) 98 | 99 | ## License 100 | 101 | See the LICENSE file 102 | -------------------------------------------------------------------------------- /Sources/Future+Operations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Future+Operations.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 03/04/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Future { 12 | /// Maps the materialized value to type `U` 13 | /// - parameter on: The ExecutionContext on which the completion closure should be called, defaults to .main 14 | /// - parameter transform: The transform closure that should map the successful value 15 | /// - returns: A new chainable Future instance 16 | /// 17 | /// ```swift 18 | /// someFuture.map({ (age: Int) -> String 19 | /// return "Age: \(age) 20 | /// }).success { print($0) } 21 | @discardableResult 22 | public func map(on context: ExecutionContext = .main, _ transform: @escaping (Value) -> U) -> Future { 23 | let mapped = Future() 24 | self.then(on: context) { result in 25 | switch result { 26 | case .success(let value): 27 | mapped.resolve(success: transform(value)) 28 | case .failure(let error): 29 | mapped.resolve(error: error) 30 | } 31 | } 32 | return mapped 33 | } 34 | 35 | /// Combines the successful result of one future with something that takes the successful result as a 36 | /// parameter and returns another future 37 | @discardableResult 38 | public func combine(with other: @escaping (Value) -> Future) -> Future { 39 | let final = Future() 40 | then { result in 41 | switch result { 42 | case .success(let value): 43 | other(value) |> final 44 | case .failure(let error): 45 | final.resolve(error: error) 46 | } 47 | 48 | } 49 | return final 50 | } 51 | 52 | /// Returns a Future of type `T` that returns when all the supplied Future of type `T` finishes, or if a 53 | /// Future returns a failure 54 | /// 55 | /// - parameter futures: List of Futures of type `T` 56 | /// 57 | /// ```swift 58 | /// Future.all([one(), two(), three()]).success { values in 59 | /// // values is an array containing the .success values from the one(), two(), three() futures 60 | /// } 61 | public static func all(_ futures: U) -> Future<[T]> where U.Iterator.Element == Future { 62 | let allFuture = Future<[T]>(on: .background) 63 | let futures = Array(futures) 64 | let mutex = Mutex() 65 | var remaining = futures.count 66 | for future in futures { 67 | future.success(on: .background) { value in 68 | mutex.locked { remaining -= 1 } 69 | if remaining <= 0 { 70 | let values = futures.flatMap({ $0.result?.value }) 71 | allFuture.resolve(success: values) 72 | } 73 | }.failure(on: .background) { error in 74 | allFuture.resolve(error: error) 75 | } 76 | } 77 | return allFuture 78 | } 79 | } 80 | 81 | infix operator |> 82 | /// Pipes the result of the left hand side Future into resolving the right hand side Future 83 | internal func |> (left: Future, right: Future) { 84 | left.success { value in 85 | right.resolve(success: value) 86 | }.failure { error in 87 | right.resolve(error: error) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Eventually.xcodeproj/xcshareddata/xcschemes/Eventually-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Eventually.xcodeproj/xcshareddata/xcschemes/Eventually-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Eventually.xcodeproj/xcshareddata/xcschemes/Eventually-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 69 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 88 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /Sources/Future.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Future.swift 3 | // Eventually 4 | // 5 | // Created by Johan Sørensen on 21/02/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// A Future represent a value that has not yet been calculated, using this class you 12 | /// observe and transform such a value when it has been materialized with a value 13 | public final class Future { 14 | public var result: FutureResult? 15 | public var isCompleted: Bool { return result != nil } 16 | 17 | private var observers: [Observable] = [] 18 | private let mutex = Mutex() 19 | private let resolveContext: ExecutionContext 20 | 21 | /// Creates a new future, call the provided resolver when the (async) task completes with 22 | /// either an FutureResult.success or FutureResult.failure in the case of errors 23 | /// 24 | /// - returns: a Future which can be passed around, mapped to another type or materialize its value once 25 | /// the value is available 26 | /// - parameter on: The ExecutionContext on which this Future should be resolved. Defaults to main queue 27 | /// - parameter resolver: The body of the Future which received a resolve closure to be called 28 | /// when the Future is realized 29 | /// 30 | /// ```swift 31 | /// Future { resolve in 32 | /// someAsyncFunc { value in 33 | /// resolve.success(value) 34 | /// } 35 | /// } 36 | public init(on context: ExecutionContext = .main, resolver: @escaping (Resolve) -> Void) { 37 | self.result = nil 38 | self.resolveContext = context 39 | 40 | context.apply { 41 | let resolve = Resolve(closure: { result in 42 | self.complete(with: result) 43 | }) 44 | resolver(resolve) 45 | } 46 | } 47 | 48 | /// Creates a new Future that can be resolve at a later time 49 | /// 50 | /// - returns: a Future which can be passed around, mapped to another type or materialize its value once 51 | /// the value is available 52 | /// - parameter on: The ExecutionContext on which this Future should be resolved. Defaults to main queue 53 | /// ```swift 54 | /// let future = Future() 55 | /// ... 56 | /// future.resolve(success: value) 57 | public init(on context: ExecutionContext = .main) { 58 | self.result = nil 59 | self.resolveContext = context 60 | } 61 | 62 | /// Resolve the future with a successful value 63 | /// 64 | /// - parameter success: The value to complete the Future with 65 | public func resolve(success value: Value) { 66 | self.resolveContext.apply { 67 | self.complete(with: .success(value)) 68 | } 69 | } 70 | 71 | /// Attempts to resolve the future, turning any thrown errors into a failing future 72 | /// 73 | /// - parameter try: Closure to evaluate for a value, if an error is thrown the future is resolve as a failure 74 | public func resolve(try closure: @escaping () throws -> Value) { 75 | self.resolveContext.apply { 76 | do { 77 | let value = try closure() 78 | self.complete(with: .success(value)) 79 | } catch { 80 | self.complete(with: .failure(error)) 81 | } 82 | } 83 | } 84 | 85 | /// Resolve the future with an error value 86 | /// 87 | /// - parameter error: The error value to complete the Future with 88 | public func resolve(error: Error) { 89 | self.resolveContext.apply { 90 | self.complete(with: .failure(error)) 91 | } 92 | } 93 | 94 | /// Calls the completion closure once the value of the Future is available to be materialized 95 | /// 96 | /// - parameter on: The ExecutionContext on which the completion closure should be called, defaults to .main 97 | /// - parameter completion: The closure which will receive the FutureResult once the Future is materialized 98 | /// - returns: A new chainable Future instance 99 | /// 100 | /// ```swift 101 | /// someFuture.then { result in 102 | /// switch result { 103 | /// case .success(let value): 104 | /// // .. do something with the Value 105 | /// case .failure(let error): 106 | /// // .. error handling 107 | /// } 108 | @discardableResult 109 | public func then(on context: ExecutionContext = .main, _ completion: @escaping (FutureResult) -> Void) -> Future { 110 | let observable = Observable(context: context, observer: completion) 111 | 112 | if let result = self.result { 113 | observable.call(result: result) 114 | } else { 115 | mutex.locked { 116 | self.observers.append(observable) 117 | } 118 | } 119 | 120 | return self 121 | } 122 | 123 | /// Calls the completion closure in case of a succesful Future completion 124 | /// 125 | /// - parameter on: The ExecutionContext on which the completion closure should be called, defaults to .main 126 | /// - parameter completion: The closure which will receive the resulting value once the Future is materialized 127 | /// to a successful value, otherwise in case of an error Result it will not be called 128 | /// - returns: A new chainable Future instance 129 | @discardableResult 130 | public func success(on context: ExecutionContext = .main, _ completion: @escaping (Value) -> Void) -> Future { 131 | return Future { resolve in 132 | self.then(on: context) { result in 133 | switch result { 134 | case .success(let value): 135 | completion(value) 136 | resolve.success(value) 137 | case .failure(let error): 138 | resolve.failure(error) 139 | } 140 | } 141 | } 142 | } 143 | 144 | /// Calls the completion closure in case of a failure Future completion 145 | /// 146 | /// - parameter on: The ExecutionContext on which the completion closure should be called, defaults to .main 147 | /// - parameter completion: The closure which will receive the resulting error if the Future materializes 148 | /// to an error, will not be called otherwise 149 | /// - returns: A new chainable Future instance 150 | @discardableResult 151 | public func failure(on context: ExecutionContext = .main, _ completion: @escaping (Error) -> Void) -> Future { 152 | return Future { resolve in 153 | self.then(on: context) { result in 154 | switch result { 155 | case .success(let value): 156 | resolve.success(value) 157 | case .failure(let error): 158 | completion(error) 159 | resolve.failure(error) 160 | } 161 | } 162 | } 163 | } 164 | 165 | private func complete(with result: FutureResult) { 166 | guard !isCompleted else { return } 167 | 168 | self.result = result 169 | 170 | var observers = mutex.locked { () -> [Observable] in 171 | let reversed = Array(self.observers.reversed()) 172 | self.observers.removeAll() 173 | return reversed 174 | } 175 | 176 | while let observer = observers.popLast() { 177 | observer.call(result: result) 178 | } 179 | } 180 | } 181 | 182 | /// :nodoc: 183 | extension Future: CustomStringConvertible { 184 | public var description: String { 185 | return "<\(type(of: self)) result: \(String(describing: result))>" 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /Tests/EventuallyTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventuallyTests.swift 3 | // EventuallyTests 4 | // 5 | // Created by Johan Sørensen on 21/02/2017. 6 | // Copyright © 2017 NRK. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Eventually 11 | 12 | class EventuallyTests: XCTestCase { 13 | func testBasics() { 14 | let stringFuture = Future { resolve in 15 | resolve.success("hello") 16 | } 17 | 18 | XCTAssert(stringFuture.isCompleted) 19 | switch stringFuture.result! { 20 | case .success(let value): 21 | XCTAssertEqual(value, "hello") 22 | case .failure: 23 | XCTFail() 24 | } 25 | } 26 | 27 | func testThen() { 28 | successFuture().then { result in 29 | switch result { 30 | case .success(let value): 31 | XCTAssertEqual(value, 42) 32 | case .failure: 33 | XCTFail() 34 | } 35 | } 36 | 37 | failingFuture().then { result in 38 | switch result { 39 | case .success: 40 | XCTFail() 41 | case .failure(let error): 42 | XCTAssert(error is TestError) 43 | } 44 | } 45 | } 46 | 47 | func testAsyncSuccess() { 48 | let wait = expectation(description: "async") 49 | 50 | successAsyncFuture().then { result in 51 | XCTAssertEqual(result.value, Optional(42)) 52 | XCTAssertNil(result.error) 53 | wait.fulfill() 54 | } 55 | waitForExpectations(timeout: 0.5, handler: nil) 56 | } 57 | 58 | func testSuccessFailureSugar() { 59 | let wait = expectation(description: "async") 60 | 61 | successAsyncFuture() 62 | .success { value in 63 | XCTAssertEqual(value, 42) 64 | wait.fulfill() 65 | }.failure { _ in 66 | XCTFail("should never be reached") 67 | } 68 | waitForExpectations(timeout: 0.5, handler: nil) 69 | } 70 | 71 | func testFailingSuccessFailureSugar() { 72 | let wait = expectation(description: "async") 73 | 74 | failingAsyncFuture() 75 | .success { _ in 76 | XCTFail("should never be reached") 77 | }.failure { error in 78 | XCTAssert(error is TestError) 79 | wait.fulfill() 80 | } 81 | waitForExpectations(timeout: 0.5, handler: nil) 82 | } 83 | 84 | func testAsyncFailure() { 85 | let wait = expectation(description: "async") 86 | 87 | failingAsyncFuture().then { result in 88 | XCTAssertNil(result.value) 89 | XCTAssertNotNil(result.error) 90 | wait.fulfill() 91 | } 92 | waitForExpectations(timeout: 0.5, handler: nil) 93 | } 94 | 95 | func testResolvingOnNonMailExecutionContext() { 96 | let future = Future(on: .background) { resolve in 97 | XCTAssertFalse(Thread.isMainThread) 98 | self.operation(completion: { val in 99 | resolve.success(val) 100 | }) 101 | } 102 | 103 | let wait = expectation(description: "async") 104 | 105 | future.then { result in 106 | XCTAssertTrue(Thread.isMainThread) 107 | wait.fulfill() 108 | } 109 | waitForExpectations(timeout: 0.5, handler: nil) 110 | } 111 | 112 | func testFulfillingMailExecutionContext() { 113 | let future = Future(on: .main) { resolve in 114 | XCTAssertTrue(Thread.isMainThread) 115 | self.operation(completion: { val in 116 | resolve.success(val) 117 | }) 118 | } 119 | 120 | let wait = expectation(description: "async") 121 | 122 | future.then(on: .background) { result in 123 | XCTAssertFalse(Thread.isMainThread) 124 | wait.fulfill() 125 | } 126 | waitForExpectations(timeout: 0.5, handler: nil) 127 | } 128 | 129 | func testAsyncMapping() { 130 | let wait = expectation(description: "async") 131 | 132 | successAsyncFuture() 133 | .map({ $0 * 2 }) 134 | .then({ result in 135 | XCTAssertEqual(result.value, Optional(84)) 136 | wait.fulfill() 137 | }) 138 | 139 | waitForExpectations(timeout: 0.5, handler: nil) 140 | } 141 | 142 | func testAsyncMappingOnContext() { 143 | let wait = expectation(description: "async") 144 | 145 | successAsyncFuture() 146 | .map(on: .background, { (value: Int) -> Int in 147 | XCTAssertFalse(Thread.isMainThread) 148 | return value * 2 149 | }) 150 | .then({ result in 151 | XCTAssertEqual(result.value, Optional(84)) 152 | wait.fulfill() 153 | }) 154 | 155 | waitForExpectations(timeout: 0.5, handler: nil) 156 | } 157 | 158 | func testAll() { 159 | let wait = expectation(description: "async") 160 | 161 | var count = 0 162 | Future.all([ 163 | successAsyncFuture(value: 2).success({ _ in count += 1 }), 164 | successAsyncFuture(value: 4).success({ _ in count += 1 }), 165 | successAsyncFuture(value: 6).success({ _ in count += 1 }), 166 | ]).success { values in 167 | // all done 168 | XCTAssertEqual(count, 3) 169 | XCTAssertEqual(values, [2, 4, 6]) 170 | wait.fulfill() 171 | } 172 | 173 | waitForExpectations(timeout: 0.5, handler: nil) 174 | } 175 | 176 | func testAllFailure() { 177 | let wait = expectation(description: "async") 178 | 179 | var count = 0 180 | func run() -> Future { 181 | return Future { resolve in 182 | DispatchQueue.global().async { 183 | count += 1 184 | resolve.success(1) 185 | } 186 | } 187 | } 188 | 189 | Future.all([ 190 | run(), 191 | failingFuture(), 192 | run(), 193 | ]).failure { error in 194 | XCTAssertEqual(count, 2) 195 | wait.fulfill() 196 | } 197 | 198 | waitForExpectations(timeout: 0.5) 199 | } 200 | 201 | func testNonClosureResolveSuccess() { 202 | let future = Future() 203 | 204 | let wait = expectation(description: "async") 205 | future.success { value in 206 | XCTAssertEqual(value, 42) 207 | wait.fulfill() 208 | } 209 | 210 | future.resolve(success: 42) 211 | waitForExpectations(timeout: 0.1, handler: nil) 212 | } 213 | 214 | func testNonClosureResolveFailure() { 215 | let future = Future() 216 | 217 | let wait = expectation(description: "async") 218 | future.failure { error in 219 | XCTAssert(error is TestError) 220 | wait.fulfill() 221 | } 222 | 223 | future.resolve(error: TestError.fail) 224 | waitForExpectations(timeout: 0.1, handler: nil) 225 | } 226 | 227 | func testFuturesCanOnlyBeResolvedOnce() { 228 | let future = Future() 229 | future.resolve(success: 42) 230 | XCTAssertEqual(future.result!.value, 42) 231 | future.resolve(success: 666) 232 | XCTAssertEqual(future.result!.value, 42) 233 | } 234 | 235 | func testThrowingFuture() { 236 | let wait1 = expectation(description: "async") 237 | let successFuture = Future() 238 | successFuture.success { value in 239 | XCTAssertEqual(value, 42) 240 | wait1.fulfill() 241 | } 242 | successFuture.resolve(try: { 243 | return 42 244 | }) 245 | 246 | let wait2 = expectation(description: "async2") 247 | let failingFuture = Future() 248 | failingFuture.failure { error in 249 | XCTAssert(failingFuture.result!.error is TestError) 250 | XCTAssertEqual(failingFuture.result!.error as! TestError, TestError.fail) 251 | wait2.fulfill() 252 | } 253 | failingFuture.resolve(try: { 254 | throw TestError.fail 255 | }) 256 | 257 | waitForExpectations(timeout: 0.1, handler: nil) 258 | } 259 | 260 | func testCombine() { 261 | func gen(shouldFail: Bool = false) -> Future { 262 | let future = Future() 263 | if !shouldFail { 264 | future.resolve(success: 42) 265 | } else { 266 | future.resolve(error: TestError.fail) 267 | } 268 | 269 | return future 270 | } 271 | func stringy(value: Int) -> Future { 272 | return Future(on: .background) { resolve in 273 | resolve.success("value is \(value)") 274 | } 275 | } 276 | func stringyFail(value: Int) -> Future { 277 | return Future(on: .background) { resolve in 278 | resolve.failure(TestError.fail2) 279 | } 280 | } 281 | 282 | let wait1 = expectation(description: "async") 283 | gen().combine(with: stringy).success { value in 284 | XCTAssertEqual("value is 42", value) 285 | wait1.fulfill() 286 | } 287 | 288 | let wait2 = expectation(description: "async") 289 | gen(shouldFail: true).combine(with: stringy).success { value in 290 | XCTFail() 291 | }.failure { error in 292 | XCTAssert(error is TestError) 293 | XCTAssertEqual(error as! TestError, TestError.fail) 294 | wait2.fulfill() 295 | } 296 | 297 | let wait3 = expectation(description: "async") 298 | gen().combine(with: stringyFail).success { value in 299 | XCTFail() 300 | }.failure { error in 301 | XCTAssert(error is TestError) 302 | XCTAssertEqual(error as! TestError, TestError.fail2) 303 | wait3.fulfill() 304 | } 305 | 306 | waitForExpectations(timeout: 0.1, handler: nil) 307 | } 308 | 309 | // MARK: - Helpers 310 | 311 | func operation(value: Int = 42, completion: @escaping (Int) -> Void) { 312 | DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(256)) { 313 | completion(value) 314 | } 315 | } 316 | 317 | func successAsyncFuture(value: Int = 42) -> Future { 318 | return Future { resolve in 319 | self.operation(value: value, completion: { val in 320 | resolve.success(val) 321 | }) 322 | } 323 | } 324 | 325 | func successFuture() -> Future { 326 | return Future { resolve in 327 | resolve.success(42) 328 | } 329 | } 330 | 331 | enum TestError: Error { 332 | case fail 333 | case fail2 334 | } 335 | 336 | func failingFuture() -> Future { 337 | return Future { resolve in 338 | resolve.failure(TestError.fail) 339 | } 340 | } 341 | 342 | func failingAsyncFuture() -> Future { 343 | return Future { resolve in 344 | DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(256)) { 345 | resolve.failure(TestError.fail) 346 | } 347 | } 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /Eventually.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 04171ED11E5CC05700E1C640 /* EventuallyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ECF1E5CC05100E1C640 /* EventuallyTests.swift */; }; 11 | 04171ED21E5CC05700E1C640 /* EventuallyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ECF1E5CC05100E1C640 /* EventuallyTests.swift */; }; 12 | 04171ED31E5CC05800E1C640 /* EventuallyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ECF1E5CC05100E1C640 /* EventuallyTests.swift */; }; 13 | 04171ED81E5CC06100E1C640 /* ExecutionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED41E5CC06100E1C640 /* ExecutionContext.swift */; }; 14 | 04171ED91E5CC06100E1C640 /* Future.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED51E5CC06100E1C640 /* Future.swift */; }; 15 | 04171EDA1E5CC06100E1C640 /* FutureResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED61E5CC06100E1C640 /* FutureResult.swift */; }; 16 | 04171EDB1E5CC06100E1C640 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED71E5CC06100E1C640 /* Observable.swift */; }; 17 | 04171EDC1E5CC06D00E1C640 /* Future.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED51E5CC06100E1C640 /* Future.swift */; }; 18 | 04171EDD1E5CC06D00E1C640 /* FutureResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED61E5CC06100E1C640 /* FutureResult.swift */; }; 19 | 04171EDE1E5CC06D00E1C640 /* ExecutionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED41E5CC06100E1C640 /* ExecutionContext.swift */; }; 20 | 04171EDF1E5CC06D00E1C640 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED71E5CC06100E1C640 /* Observable.swift */; }; 21 | 04171EE01E5CC06D00E1C640 /* Future.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED51E5CC06100E1C640 /* Future.swift */; }; 22 | 04171EE11E5CC06D00E1C640 /* FutureResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED61E5CC06100E1C640 /* FutureResult.swift */; }; 23 | 04171EE21E5CC06D00E1C640 /* ExecutionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED41E5CC06100E1C640 /* ExecutionContext.swift */; }; 24 | 04171EE31E5CC06D00E1C640 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED71E5CC06100E1C640 /* Observable.swift */; }; 25 | 04171EE41E5CC06E00E1C640 /* Future.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED51E5CC06100E1C640 /* Future.swift */; }; 26 | 04171EE51E5CC06E00E1C640 /* FutureResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED61E5CC06100E1C640 /* FutureResult.swift */; }; 27 | 04171EE61E5CC06E00E1C640 /* ExecutionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED41E5CC06100E1C640 /* ExecutionContext.swift */; }; 28 | 04171EE71E5CC06E00E1C640 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171ED71E5CC06100E1C640 /* Observable.swift */; }; 29 | 04171EE91E5CDC9500E1C640 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171EE81E5CDC9500E1C640 /* Mutex.swift */; }; 30 | 04171EEA1E5CDC9500E1C640 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171EE81E5CDC9500E1C640 /* Mutex.swift */; }; 31 | 04171EEB1E5CDC9500E1C640 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171EE81E5CDC9500E1C640 /* Mutex.swift */; }; 32 | 04171EEC1E5CDC9500E1C640 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04171EE81E5CDC9500E1C640 /* Mutex.swift */; }; 33 | 52D6D9871BEFF229002C0205 /* Eventually.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* Eventually.framework */; }; 34 | D917F6B01E928638000B1232 /* Future+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D917F6AF1E928638000B1232 /* Future+Operations.swift */; }; 35 | D917F6B11E928638000B1232 /* Future+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D917F6AF1E928638000B1232 /* Future+Operations.swift */; }; 36 | D917F6B21E928638000B1232 /* Future+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D917F6AF1E928638000B1232 /* Future+Operations.swift */; }; 37 | D917F6B31E928638000B1232 /* Future+Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D917F6AF1E928638000B1232 /* Future+Operations.swift */; }; 38 | D9D9DB8C1E66B2FF0033406B /* Resolve.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9D9DB8B1E66B2FF0033406B /* Resolve.swift */; }; 39 | D9D9DB8D1E66B2FF0033406B /* Resolve.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9D9DB8B1E66B2FF0033406B /* Resolve.swift */; }; 40 | D9D9DB8E1E66B2FF0033406B /* Resolve.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9D9DB8B1E66B2FF0033406B /* Resolve.swift */; }; 41 | D9D9DB8F1E66B2FF0033406B /* Resolve.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9D9DB8B1E66B2FF0033406B /* Resolve.swift */; }; 42 | DD7502881C68FEDE006590AF /* Eventually.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6DA0F1BF000BD002C0205 /* Eventually.framework */; }; 43 | DD7502921C690C7A006590AF /* Eventually.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* Eventually.framework */; }; 44 | /* End PBXBuildFile section */ 45 | 46 | /* Begin PBXContainerItemProxy section */ 47 | 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 50 | proxyType = 1; 51 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205; 52 | remoteInfo = Eventually; 53 | }; 54 | DD7502801C68FCFC006590AF /* PBXContainerItemProxy */ = { 55 | isa = PBXContainerItemProxy; 56 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 57 | proxyType = 1; 58 | remoteGlobalIDString = 52D6DA0E1BF000BD002C0205; 59 | remoteInfo = "Eventually-macOS"; 60 | }; 61 | DD7502931C690C7A006590AF /* PBXContainerItemProxy */ = { 62 | isa = PBXContainerItemProxy; 63 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 64 | proxyType = 1; 65 | remoteGlobalIDString = 52D6D9EF1BEFFFBE002C0205; 66 | remoteInfo = "Eventually-tvOS"; 67 | }; 68 | /* End PBXContainerItemProxy section */ 69 | 70 | /* Begin PBXFileReference section */ 71 | 04171ECF1E5CC05100E1C640 /* EventuallyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventuallyTests.swift; sourceTree = ""; }; 72 | 04171ED41E5CC06100E1C640 /* ExecutionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExecutionContext.swift; sourceTree = ""; }; 73 | 04171ED51E5CC06100E1C640 /* Future.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Future.swift; sourceTree = ""; }; 74 | 04171ED61E5CC06100E1C640 /* FutureResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FutureResult.swift; sourceTree = ""; }; 75 | 04171ED71E5CC06100E1C640 /* Observable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; 76 | 04171EE81E5CDC9500E1C640 /* Mutex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; 77 | 52D6D97C1BEFF229002C0205 /* Eventually.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Eventually.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 52D6D9861BEFF229002C0205 /* Eventually-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Eventually-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 79 | 52D6D9E21BEFFF6E002C0205 /* Eventually.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Eventually.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 52D6D9F01BEFFFBE002C0205 /* Eventually.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Eventually.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 52D6DA0F1BF000BD002C0205 /* Eventually.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Eventually.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | AD2FAA261CD0B6D800659CF4 /* Eventually.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Eventually.plist; sourceTree = ""; }; 83 | AD2FAA281CD0B6E100659CF4 /* EventuallyTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = EventuallyTests.plist; sourceTree = ""; }; 84 | D917F6AF1E928638000B1232 /* Future+Operations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Future+Operations.swift"; sourceTree = ""; }; 85 | D9ADA01F1E694B0E003C91BD /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 86 | D9D9DB8B1E66B2FF0033406B /* Resolve.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Resolve.swift; sourceTree = ""; }; 87 | DD75027A1C68FCFC006590AF /* Eventually-macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Eventually-macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | DD75028D1C690C7A006590AF /* Eventually-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Eventually-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | /* End PBXFileReference section */ 90 | 91 | /* Begin PBXFrameworksBuildPhase section */ 92 | 52D6D9781BEFF229002C0205 /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 52D6D9831BEFF229002C0205 /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | 52D6D9871BEFF229002C0205 /* Eventually.framework in Frameworks */, 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */ = { 108 | isa = PBXFrameworksBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | 52D6DA0B1BF000BD002C0205 /* Frameworks */ = { 122 | isa = PBXFrameworksBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | ); 126 | runOnlyForDeploymentPostprocessing = 0; 127 | }; 128 | DD7502771C68FCFC006590AF /* Frameworks */ = { 129 | isa = PBXFrameworksBuildPhase; 130 | buildActionMask = 2147483647; 131 | files = ( 132 | DD7502881C68FEDE006590AF /* Eventually.framework in Frameworks */, 133 | ); 134 | runOnlyForDeploymentPostprocessing = 0; 135 | }; 136 | DD75028A1C690C7A006590AF /* Frameworks */ = { 137 | isa = PBXFrameworksBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | DD7502921C690C7A006590AF /* Eventually.framework in Frameworks */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXFrameworksBuildPhase section */ 145 | 146 | /* Begin PBXGroup section */ 147 | 04171ECD1E5CBFD600E1C640 /* Sources */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 04171ED51E5CC06100E1C640 /* Future.swift */, 151 | D917F6AF1E928638000B1232 /* Future+Operations.swift */, 152 | 04171ED61E5CC06100E1C640 /* FutureResult.swift */, 153 | 04171ED41E5CC06100E1C640 /* ExecutionContext.swift */, 154 | D9D9DB8B1E66B2FF0033406B /* Resolve.swift */, 155 | 04171ED71E5CC06100E1C640 /* Observable.swift */, 156 | 04171EE81E5CDC9500E1C640 /* Mutex.swift */, 157 | ); 158 | path = Sources; 159 | sourceTree = ""; 160 | }; 161 | 04171ECE1E5CBFDD00E1C640 /* Tests */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 04171ECF1E5CC05100E1C640 /* EventuallyTests.swift */, 165 | ); 166 | path = Tests; 167 | sourceTree = ""; 168 | }; 169 | 52D6D9721BEFF229002C0205 = { 170 | isa = PBXGroup; 171 | children = ( 172 | D9ADA01F1E694B0E003C91BD /* README.md */, 173 | 04171ECD1E5CBFD600E1C640 /* Sources */, 174 | 04171ECE1E5CBFDD00E1C640 /* Tests */, 175 | 52D6D99C1BEFF38C002C0205 /* Configs */, 176 | 52D6D97D1BEFF229002C0205 /* Products */, 177 | ); 178 | sourceTree = ""; 179 | }; 180 | 52D6D97D1BEFF229002C0205 /* Products */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | 52D6D97C1BEFF229002C0205 /* Eventually.framework */, 184 | 52D6D9861BEFF229002C0205 /* Eventually-iOS Tests.xctest */, 185 | 52D6D9E21BEFFF6E002C0205 /* Eventually.framework */, 186 | 52D6D9F01BEFFFBE002C0205 /* Eventually.framework */, 187 | 52D6DA0F1BF000BD002C0205 /* Eventually.framework */, 188 | DD75027A1C68FCFC006590AF /* Eventually-macOS Tests.xctest */, 189 | DD75028D1C690C7A006590AF /* Eventually-tvOS Tests.xctest */, 190 | ); 191 | name = Products; 192 | sourceTree = ""; 193 | }; 194 | 52D6D99C1BEFF38C002C0205 /* Configs */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | DD7502721C68FC1B006590AF /* Frameworks */, 198 | DD7502731C68FC20006590AF /* Tests */, 199 | ); 200 | path = Configs; 201 | sourceTree = ""; 202 | }; 203 | DD7502721C68FC1B006590AF /* Frameworks */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | AD2FAA261CD0B6D800659CF4 /* Eventually.plist */, 207 | ); 208 | name = Frameworks; 209 | sourceTree = ""; 210 | }; 211 | DD7502731C68FC20006590AF /* Tests */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | AD2FAA281CD0B6E100659CF4 /* EventuallyTests.plist */, 215 | ); 216 | name = Tests; 217 | sourceTree = ""; 218 | }; 219 | /* End PBXGroup section */ 220 | 221 | /* Begin PBXHeadersBuildPhase section */ 222 | 52D6D9791BEFF229002C0205 /* Headers */ = { 223 | isa = PBXHeadersBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | 52D6D9DF1BEFFF6E002C0205 /* Headers */ = { 230 | isa = PBXHeadersBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | 52D6D9ED1BEFFFBE002C0205 /* Headers */ = { 237 | isa = PBXHeadersBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | 52D6DA0C1BF000BD002C0205 /* Headers */ = { 244 | isa = PBXHeadersBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXHeadersBuildPhase section */ 251 | 252 | /* Begin PBXNativeTarget section */ 253 | 52D6D97B1BEFF229002C0205 /* Eventually-iOS */ = { 254 | isa = PBXNativeTarget; 255 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Eventually-iOS" */; 256 | buildPhases = ( 257 | 52D6D9771BEFF229002C0205 /* Sources */, 258 | 52D6D9781BEFF229002C0205 /* Frameworks */, 259 | 52D6D9791BEFF229002C0205 /* Headers */, 260 | 52D6D97A1BEFF229002C0205 /* Resources */, 261 | ); 262 | buildRules = ( 263 | ); 264 | dependencies = ( 265 | ); 266 | name = "Eventually-iOS"; 267 | productName = Eventually; 268 | productReference = 52D6D97C1BEFF229002C0205 /* Eventually.framework */; 269 | productType = "com.apple.product-type.framework"; 270 | }; 271 | 52D6D9851BEFF229002C0205 /* Eventually-iOS Tests */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Eventually-iOS Tests" */; 274 | buildPhases = ( 275 | 52D6D9821BEFF229002C0205 /* Sources */, 276 | 52D6D9831BEFF229002C0205 /* Frameworks */, 277 | 52D6D9841BEFF229002C0205 /* Resources */, 278 | ); 279 | buildRules = ( 280 | ); 281 | dependencies = ( 282 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */, 283 | ); 284 | name = "Eventually-iOS Tests"; 285 | productName = EventuallyTests; 286 | productReference = 52D6D9861BEFF229002C0205 /* Eventually-iOS Tests.xctest */; 287 | productType = "com.apple.product-type.bundle.unit-test"; 288 | }; 289 | 52D6D9E11BEFFF6E002C0205 /* Eventually-watchOS */ = { 290 | isa = PBXNativeTarget; 291 | buildConfigurationList = 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "Eventually-watchOS" */; 292 | buildPhases = ( 293 | 52D6D9DD1BEFFF6E002C0205 /* Sources */, 294 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */, 295 | 52D6D9DF1BEFFF6E002C0205 /* Headers */, 296 | 52D6D9E01BEFFF6E002C0205 /* Resources */, 297 | ); 298 | buildRules = ( 299 | ); 300 | dependencies = ( 301 | ); 302 | name = "Eventually-watchOS"; 303 | productName = "Eventually-watchOS"; 304 | productReference = 52D6D9E21BEFFF6E002C0205 /* Eventually.framework */; 305 | productType = "com.apple.product-type.framework"; 306 | }; 307 | 52D6D9EF1BEFFFBE002C0205 /* Eventually-tvOS */ = { 308 | isa = PBXNativeTarget; 309 | buildConfigurationList = 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "Eventually-tvOS" */; 310 | buildPhases = ( 311 | 52D6D9EB1BEFFFBE002C0205 /* Sources */, 312 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */, 313 | 52D6D9ED1BEFFFBE002C0205 /* Headers */, 314 | 52D6D9EE1BEFFFBE002C0205 /* Resources */, 315 | ); 316 | buildRules = ( 317 | ); 318 | dependencies = ( 319 | ); 320 | name = "Eventually-tvOS"; 321 | productName = "Eventually-tvOS"; 322 | productReference = 52D6D9F01BEFFFBE002C0205 /* Eventually.framework */; 323 | productType = "com.apple.product-type.framework"; 324 | }; 325 | 52D6DA0E1BF000BD002C0205 /* Eventually-macOS */ = { 326 | isa = PBXNativeTarget; 327 | buildConfigurationList = 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "Eventually-macOS" */; 328 | buildPhases = ( 329 | 52D6DA0A1BF000BD002C0205 /* Sources */, 330 | 52D6DA0B1BF000BD002C0205 /* Frameworks */, 331 | 52D6DA0C1BF000BD002C0205 /* Headers */, 332 | 52D6DA0D1BF000BD002C0205 /* Resources */, 333 | ); 334 | buildRules = ( 335 | ); 336 | dependencies = ( 337 | ); 338 | name = "Eventually-macOS"; 339 | productName = "Eventually-macOS"; 340 | productReference = 52D6DA0F1BF000BD002C0205 /* Eventually.framework */; 341 | productType = "com.apple.product-type.framework"; 342 | }; 343 | DD7502791C68FCFC006590AF /* Eventually-macOS Tests */ = { 344 | isa = PBXNativeTarget; 345 | buildConfigurationList = DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "Eventually-macOS Tests" */; 346 | buildPhases = ( 347 | DD7502761C68FCFC006590AF /* Sources */, 348 | DD7502771C68FCFC006590AF /* Frameworks */, 349 | DD7502781C68FCFC006590AF /* Resources */, 350 | ); 351 | buildRules = ( 352 | ); 353 | dependencies = ( 354 | DD7502811C68FCFC006590AF /* PBXTargetDependency */, 355 | ); 356 | name = "Eventually-macOS Tests"; 357 | productName = "Eventually-OS Tests"; 358 | productReference = DD75027A1C68FCFC006590AF /* Eventually-macOS Tests.xctest */; 359 | productType = "com.apple.product-type.bundle.unit-test"; 360 | }; 361 | DD75028C1C690C7A006590AF /* Eventually-tvOS Tests */ = { 362 | isa = PBXNativeTarget; 363 | buildConfigurationList = DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "Eventually-tvOS Tests" */; 364 | buildPhases = ( 365 | DD7502891C690C7A006590AF /* Sources */, 366 | DD75028A1C690C7A006590AF /* Frameworks */, 367 | DD75028B1C690C7A006590AF /* Resources */, 368 | ); 369 | buildRules = ( 370 | ); 371 | dependencies = ( 372 | DD7502941C690C7A006590AF /* PBXTargetDependency */, 373 | ); 374 | name = "Eventually-tvOS Tests"; 375 | productName = "Eventually-tvOS Tests"; 376 | productReference = DD75028D1C690C7A006590AF /* Eventually-tvOS Tests.xctest */; 377 | productType = "com.apple.product-type.bundle.unit-test"; 378 | }; 379 | /* End PBXNativeTarget section */ 380 | 381 | /* Begin PBXProject section */ 382 | 52D6D9731BEFF229002C0205 /* Project object */ = { 383 | isa = PBXProject; 384 | attributes = { 385 | LastSwiftUpdateCheck = 0720; 386 | LastUpgradeCheck = 0900; 387 | ORGANIZATIONNAME = NRK; 388 | TargetAttributes = { 389 | 52D6D97B1BEFF229002C0205 = { 390 | CreatedOnToolsVersion = 7.1; 391 | LastSwiftMigration = 0900; 392 | }; 393 | 52D6D9851BEFF229002C0205 = { 394 | CreatedOnToolsVersion = 7.1; 395 | LastSwiftMigration = 0900; 396 | }; 397 | 52D6D9E11BEFFF6E002C0205 = { 398 | CreatedOnToolsVersion = 7.1; 399 | LastSwiftMigration = 0800; 400 | }; 401 | 52D6D9EF1BEFFFBE002C0205 = { 402 | CreatedOnToolsVersion = 7.1; 403 | LastSwiftMigration = 0800; 404 | }; 405 | 52D6DA0E1BF000BD002C0205 = { 406 | CreatedOnToolsVersion = 7.1; 407 | LastSwiftMigration = 0800; 408 | }; 409 | DD7502791C68FCFC006590AF = { 410 | CreatedOnToolsVersion = 7.2.1; 411 | LastSwiftMigration = 0800; 412 | }; 413 | DD75028C1C690C7A006590AF = { 414 | CreatedOnToolsVersion = 7.2.1; 415 | LastSwiftMigration = 0800; 416 | }; 417 | }; 418 | }; 419 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "Eventually" */; 420 | compatibilityVersion = "Xcode 6.3"; 421 | developmentRegion = English; 422 | hasScannedForEncodings = 0; 423 | knownRegions = ( 424 | en, 425 | ); 426 | mainGroup = 52D6D9721BEFF229002C0205; 427 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */; 428 | projectDirPath = ""; 429 | projectRoot = ""; 430 | targets = ( 431 | 52D6D97B1BEFF229002C0205 /* Eventually-iOS */, 432 | 52D6DA0E1BF000BD002C0205 /* Eventually-macOS */, 433 | 52D6D9E11BEFFF6E002C0205 /* Eventually-watchOS */, 434 | 52D6D9EF1BEFFFBE002C0205 /* Eventually-tvOS */, 435 | 52D6D9851BEFF229002C0205 /* Eventually-iOS Tests */, 436 | DD7502791C68FCFC006590AF /* Eventually-macOS Tests */, 437 | DD75028C1C690C7A006590AF /* Eventually-tvOS Tests */, 438 | ); 439 | }; 440 | /* End PBXProject section */ 441 | 442 | /* Begin PBXResourcesBuildPhase section */ 443 | 52D6D97A1BEFF229002C0205 /* Resources */ = { 444 | isa = PBXResourcesBuildPhase; 445 | buildActionMask = 2147483647; 446 | files = ( 447 | ); 448 | runOnlyForDeploymentPostprocessing = 0; 449 | }; 450 | 52D6D9841BEFF229002C0205 /* Resources */ = { 451 | isa = PBXResourcesBuildPhase; 452 | buildActionMask = 2147483647; 453 | files = ( 454 | ); 455 | runOnlyForDeploymentPostprocessing = 0; 456 | }; 457 | 52D6D9E01BEFFF6E002C0205 /* Resources */ = { 458 | isa = PBXResourcesBuildPhase; 459 | buildActionMask = 2147483647; 460 | files = ( 461 | ); 462 | runOnlyForDeploymentPostprocessing = 0; 463 | }; 464 | 52D6D9EE1BEFFFBE002C0205 /* Resources */ = { 465 | isa = PBXResourcesBuildPhase; 466 | buildActionMask = 2147483647; 467 | files = ( 468 | ); 469 | runOnlyForDeploymentPostprocessing = 0; 470 | }; 471 | 52D6DA0D1BF000BD002C0205 /* Resources */ = { 472 | isa = PBXResourcesBuildPhase; 473 | buildActionMask = 2147483647; 474 | files = ( 475 | ); 476 | runOnlyForDeploymentPostprocessing = 0; 477 | }; 478 | DD7502781C68FCFC006590AF /* Resources */ = { 479 | isa = PBXResourcesBuildPhase; 480 | buildActionMask = 2147483647; 481 | files = ( 482 | ); 483 | runOnlyForDeploymentPostprocessing = 0; 484 | }; 485 | DD75028B1C690C7A006590AF /* Resources */ = { 486 | isa = PBXResourcesBuildPhase; 487 | buildActionMask = 2147483647; 488 | files = ( 489 | ); 490 | runOnlyForDeploymentPostprocessing = 0; 491 | }; 492 | /* End PBXResourcesBuildPhase section */ 493 | 494 | /* Begin PBXSourcesBuildPhase section */ 495 | 52D6D9771BEFF229002C0205 /* Sources */ = { 496 | isa = PBXSourcesBuildPhase; 497 | buildActionMask = 2147483647; 498 | files = ( 499 | D9D9DB8C1E66B2FF0033406B /* Resolve.swift in Sources */, 500 | 04171EE91E5CDC9500E1C640 /* Mutex.swift in Sources */, 501 | 04171EDB1E5CC06100E1C640 /* Observable.swift in Sources */, 502 | 04171ED91E5CC06100E1C640 /* Future.swift in Sources */, 503 | 04171EDA1E5CC06100E1C640 /* FutureResult.swift in Sources */, 504 | D917F6B01E928638000B1232 /* Future+Operations.swift in Sources */, 505 | 04171ED81E5CC06100E1C640 /* ExecutionContext.swift in Sources */, 506 | ); 507 | runOnlyForDeploymentPostprocessing = 0; 508 | }; 509 | 52D6D9821BEFF229002C0205 /* Sources */ = { 510 | isa = PBXSourcesBuildPhase; 511 | buildActionMask = 2147483647; 512 | files = ( 513 | 04171ED11E5CC05700E1C640 /* EventuallyTests.swift in Sources */, 514 | ); 515 | runOnlyForDeploymentPostprocessing = 0; 516 | }; 517 | 52D6D9DD1BEFFF6E002C0205 /* Sources */ = { 518 | isa = PBXSourcesBuildPhase; 519 | buildActionMask = 2147483647; 520 | files = ( 521 | D9D9DB8E1E66B2FF0033406B /* Resolve.swift in Sources */, 522 | 04171EEB1E5CDC9500E1C640 /* Mutex.swift in Sources */, 523 | 04171EE31E5CC06D00E1C640 /* Observable.swift in Sources */, 524 | 04171EE01E5CC06D00E1C640 /* Future.swift in Sources */, 525 | 04171EE21E5CC06D00E1C640 /* ExecutionContext.swift in Sources */, 526 | D917F6B21E928638000B1232 /* Future+Operations.swift in Sources */, 527 | 04171EE11E5CC06D00E1C640 /* FutureResult.swift in Sources */, 528 | ); 529 | runOnlyForDeploymentPostprocessing = 0; 530 | }; 531 | 52D6D9EB1BEFFFBE002C0205 /* Sources */ = { 532 | isa = PBXSourcesBuildPhase; 533 | buildActionMask = 2147483647; 534 | files = ( 535 | D9D9DB8F1E66B2FF0033406B /* Resolve.swift in Sources */, 536 | 04171EEC1E5CDC9500E1C640 /* Mutex.swift in Sources */, 537 | 04171EDF1E5CC06D00E1C640 /* Observable.swift in Sources */, 538 | 04171EDC1E5CC06D00E1C640 /* Future.swift in Sources */, 539 | 04171EDE1E5CC06D00E1C640 /* ExecutionContext.swift in Sources */, 540 | D917F6B31E928638000B1232 /* Future+Operations.swift in Sources */, 541 | 04171EDD1E5CC06D00E1C640 /* FutureResult.swift in Sources */, 542 | ); 543 | runOnlyForDeploymentPostprocessing = 0; 544 | }; 545 | 52D6DA0A1BF000BD002C0205 /* Sources */ = { 546 | isa = PBXSourcesBuildPhase; 547 | buildActionMask = 2147483647; 548 | files = ( 549 | D9D9DB8D1E66B2FF0033406B /* Resolve.swift in Sources */, 550 | 04171EEA1E5CDC9500E1C640 /* Mutex.swift in Sources */, 551 | 04171EE71E5CC06E00E1C640 /* Observable.swift in Sources */, 552 | 04171EE41E5CC06E00E1C640 /* Future.swift in Sources */, 553 | 04171EE61E5CC06E00E1C640 /* ExecutionContext.swift in Sources */, 554 | D917F6B11E928638000B1232 /* Future+Operations.swift in Sources */, 555 | 04171EE51E5CC06E00E1C640 /* FutureResult.swift in Sources */, 556 | ); 557 | runOnlyForDeploymentPostprocessing = 0; 558 | }; 559 | DD7502761C68FCFC006590AF /* Sources */ = { 560 | isa = PBXSourcesBuildPhase; 561 | buildActionMask = 2147483647; 562 | files = ( 563 | 04171ED21E5CC05700E1C640 /* EventuallyTests.swift in Sources */, 564 | ); 565 | runOnlyForDeploymentPostprocessing = 0; 566 | }; 567 | DD7502891C690C7A006590AF /* Sources */ = { 568 | isa = PBXSourcesBuildPhase; 569 | buildActionMask = 2147483647; 570 | files = ( 571 | 04171ED31E5CC05800E1C640 /* EventuallyTests.swift in Sources */, 572 | ); 573 | runOnlyForDeploymentPostprocessing = 0; 574 | }; 575 | /* End PBXSourcesBuildPhase section */ 576 | 577 | /* Begin PBXTargetDependency section */ 578 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = { 579 | isa = PBXTargetDependency; 580 | target = 52D6D97B1BEFF229002C0205 /* Eventually-iOS */; 581 | targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */; 582 | }; 583 | DD7502811C68FCFC006590AF /* PBXTargetDependency */ = { 584 | isa = PBXTargetDependency; 585 | target = 52D6DA0E1BF000BD002C0205 /* Eventually-macOS */; 586 | targetProxy = DD7502801C68FCFC006590AF /* PBXContainerItemProxy */; 587 | }; 588 | DD7502941C690C7A006590AF /* PBXTargetDependency */ = { 589 | isa = PBXTargetDependency; 590 | target = 52D6D9EF1BEFFFBE002C0205 /* Eventually-tvOS */; 591 | targetProxy = DD7502931C690C7A006590AF /* PBXContainerItemProxy */; 592 | }; 593 | /* End PBXTargetDependency section */ 594 | 595 | /* Begin XCBuildConfiguration section */ 596 | 52D6D98E1BEFF229002C0205 /* Debug */ = { 597 | isa = XCBuildConfiguration; 598 | buildSettings = { 599 | ALWAYS_SEARCH_USER_PATHS = NO; 600 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 601 | CLANG_CXX_LIBRARY = "libc++"; 602 | CLANG_ENABLE_MODULES = YES; 603 | CLANG_ENABLE_OBJC_ARC = YES; 604 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 605 | CLANG_WARN_BOOL_CONVERSION = YES; 606 | CLANG_WARN_COMMA = YES; 607 | CLANG_WARN_CONSTANT_CONVERSION = YES; 608 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 609 | CLANG_WARN_EMPTY_BODY = YES; 610 | CLANG_WARN_ENUM_CONVERSION = YES; 611 | CLANG_WARN_INFINITE_RECURSION = YES; 612 | CLANG_WARN_INT_CONVERSION = YES; 613 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 614 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 615 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 616 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 617 | CLANG_WARN_STRICT_PROTOTYPES = YES; 618 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 619 | CLANG_WARN_UNREACHABLE_CODE = YES; 620 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 621 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 622 | COPY_PHASE_STRIP = NO; 623 | CURRENT_PROJECT_VERSION = 1; 624 | DEBUG_INFORMATION_FORMAT = dwarf; 625 | ENABLE_STRICT_OBJC_MSGSEND = YES; 626 | ENABLE_TESTABILITY = YES; 627 | GCC_C_LANGUAGE_STANDARD = gnu99; 628 | GCC_DYNAMIC_NO_PIC = NO; 629 | GCC_NO_COMMON_BLOCKS = YES; 630 | GCC_OPTIMIZATION_LEVEL = 0; 631 | GCC_PREPROCESSOR_DEFINITIONS = ( 632 | "DEBUG=1", 633 | "$(inherited)", 634 | ); 635 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 636 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 637 | GCC_WARN_UNDECLARED_SELECTOR = YES; 638 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 639 | GCC_WARN_UNUSED_FUNCTION = YES; 640 | GCC_WARN_UNUSED_VARIABLE = YES; 641 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 642 | MTL_ENABLE_DEBUG_INFO = YES; 643 | ONLY_ACTIVE_ARCH = YES; 644 | SDKROOT = iphoneos; 645 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 646 | SWIFT_VERSION = 3.0; 647 | TARGETED_DEVICE_FAMILY = "1,2"; 648 | VERSIONING_SYSTEM = "apple-generic"; 649 | VERSION_INFO_PREFIX = ""; 650 | }; 651 | name = Debug; 652 | }; 653 | 52D6D98F1BEFF229002C0205 /* Release */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | ALWAYS_SEARCH_USER_PATHS = NO; 657 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 658 | CLANG_CXX_LIBRARY = "libc++"; 659 | CLANG_ENABLE_MODULES = YES; 660 | CLANG_ENABLE_OBJC_ARC = YES; 661 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 662 | CLANG_WARN_BOOL_CONVERSION = YES; 663 | CLANG_WARN_COMMA = YES; 664 | CLANG_WARN_CONSTANT_CONVERSION = YES; 665 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 666 | CLANG_WARN_EMPTY_BODY = YES; 667 | CLANG_WARN_ENUM_CONVERSION = YES; 668 | CLANG_WARN_INFINITE_RECURSION = YES; 669 | CLANG_WARN_INT_CONVERSION = YES; 670 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 671 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 672 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 673 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 674 | CLANG_WARN_STRICT_PROTOTYPES = YES; 675 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 676 | CLANG_WARN_UNREACHABLE_CODE = YES; 677 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 678 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 679 | COPY_PHASE_STRIP = NO; 680 | CURRENT_PROJECT_VERSION = 1; 681 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 682 | ENABLE_NS_ASSERTIONS = NO; 683 | ENABLE_STRICT_OBJC_MSGSEND = YES; 684 | GCC_C_LANGUAGE_STANDARD = gnu99; 685 | GCC_NO_COMMON_BLOCKS = YES; 686 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 687 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 688 | GCC_WARN_UNDECLARED_SELECTOR = YES; 689 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 690 | GCC_WARN_UNUSED_FUNCTION = YES; 691 | GCC_WARN_UNUSED_VARIABLE = YES; 692 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 693 | MTL_ENABLE_DEBUG_INFO = NO; 694 | SDKROOT = iphoneos; 695 | SWIFT_VERSION = 3.0; 696 | TARGETED_DEVICE_FAMILY = "1,2"; 697 | VALIDATE_PRODUCT = YES; 698 | VERSIONING_SYSTEM = "apple-generic"; 699 | VERSION_INFO_PREFIX = ""; 700 | }; 701 | name = Release; 702 | }; 703 | 52D6D9911BEFF229002C0205 /* Debug */ = { 704 | isa = XCBuildConfiguration; 705 | buildSettings = { 706 | APPLICATION_EXTENSION_API_ONLY = YES; 707 | CLANG_ENABLE_MODULES = YES; 708 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 709 | DEFINES_MODULE = YES; 710 | DYLIB_COMPATIBILITY_VERSION = 1; 711 | DYLIB_CURRENT_VERSION = 1; 712 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 713 | INFOPLIST_FILE = Configs/Eventually.plist; 714 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 715 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 716 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 717 | ONLY_ACTIVE_ARCH = NO; 718 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-iOS"; 719 | PRODUCT_NAME = Eventually; 720 | SKIP_INSTALL = YES; 721 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 722 | SWIFT_VERSION = 4.0; 723 | }; 724 | name = Debug; 725 | }; 726 | 52D6D9921BEFF229002C0205 /* Release */ = { 727 | isa = XCBuildConfiguration; 728 | buildSettings = { 729 | APPLICATION_EXTENSION_API_ONLY = YES; 730 | CLANG_ENABLE_MODULES = YES; 731 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 732 | DEFINES_MODULE = YES; 733 | DYLIB_COMPATIBILITY_VERSION = 1; 734 | DYLIB_CURRENT_VERSION = 1; 735 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 736 | INFOPLIST_FILE = Configs/Eventually.plist; 737 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 738 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 739 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 740 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-iOS"; 741 | PRODUCT_NAME = Eventually; 742 | SKIP_INSTALL = YES; 743 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 744 | SWIFT_VERSION = 4.0; 745 | }; 746 | name = Release; 747 | }; 748 | 52D6D9941BEFF229002C0205 /* Debug */ = { 749 | isa = XCBuildConfiguration; 750 | buildSettings = { 751 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 752 | CLANG_ENABLE_MODULES = YES; 753 | INFOPLIST_FILE = Configs/EventuallyTests.plist; 754 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 755 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-iOS-Tests"; 756 | PRODUCT_NAME = "$(TARGET_NAME)"; 757 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 758 | SWIFT_VERSION = 4.0; 759 | }; 760 | name = Debug; 761 | }; 762 | 52D6D9951BEFF229002C0205 /* Release */ = { 763 | isa = XCBuildConfiguration; 764 | buildSettings = { 765 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 766 | CLANG_ENABLE_MODULES = YES; 767 | INFOPLIST_FILE = Configs/EventuallyTests.plist; 768 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 769 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-iOS-Tests"; 770 | PRODUCT_NAME = "$(TARGET_NAME)"; 771 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 772 | SWIFT_VERSION = 4.0; 773 | }; 774 | name = Release; 775 | }; 776 | 52D6D9E81BEFFF6E002C0205 /* Debug */ = { 777 | isa = XCBuildConfiguration; 778 | buildSettings = { 779 | APPLICATION_EXTENSION_API_ONLY = YES; 780 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 781 | DEFINES_MODULE = YES; 782 | DYLIB_COMPATIBILITY_VERSION = 1; 783 | DYLIB_CURRENT_VERSION = 1; 784 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 785 | INFOPLIST_FILE = Configs/Eventually.plist; 786 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 787 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 788 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-watchOS"; 789 | PRODUCT_NAME = Eventually; 790 | SDKROOT = watchos; 791 | SKIP_INSTALL = YES; 792 | SWIFT_VERSION = 3.0; 793 | TARGETED_DEVICE_FAMILY = 4; 794 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 795 | }; 796 | name = Debug; 797 | }; 798 | 52D6D9E91BEFFF6E002C0205 /* Release */ = { 799 | isa = XCBuildConfiguration; 800 | buildSettings = { 801 | APPLICATION_EXTENSION_API_ONLY = YES; 802 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 803 | DEFINES_MODULE = YES; 804 | DYLIB_COMPATIBILITY_VERSION = 1; 805 | DYLIB_CURRENT_VERSION = 1; 806 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 807 | INFOPLIST_FILE = Configs/Eventually.plist; 808 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 809 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 810 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-watchOS"; 811 | PRODUCT_NAME = Eventually; 812 | SDKROOT = watchos; 813 | SKIP_INSTALL = YES; 814 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 815 | SWIFT_VERSION = 3.0; 816 | TARGETED_DEVICE_FAMILY = 4; 817 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 818 | }; 819 | name = Release; 820 | }; 821 | 52D6DA021BEFFFBE002C0205 /* Debug */ = { 822 | isa = XCBuildConfiguration; 823 | buildSettings = { 824 | APPLICATION_EXTENSION_API_ONLY = YES; 825 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 826 | DEFINES_MODULE = YES; 827 | DYLIB_COMPATIBILITY_VERSION = 1; 828 | DYLIB_CURRENT_VERSION = 1; 829 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 830 | INFOPLIST_FILE = Configs/Eventually.plist; 831 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 832 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 833 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-tvOS"; 834 | PRODUCT_NAME = Eventually; 835 | SDKROOT = appletvos; 836 | SKIP_INSTALL = YES; 837 | SWIFT_VERSION = 3.0; 838 | TARGETED_DEVICE_FAMILY = 3; 839 | TVOS_DEPLOYMENT_TARGET = 9.0; 840 | }; 841 | name = Debug; 842 | }; 843 | 52D6DA031BEFFFBE002C0205 /* Release */ = { 844 | isa = XCBuildConfiguration; 845 | buildSettings = { 846 | APPLICATION_EXTENSION_API_ONLY = YES; 847 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 848 | DEFINES_MODULE = YES; 849 | DYLIB_COMPATIBILITY_VERSION = 1; 850 | DYLIB_CURRENT_VERSION = 1; 851 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 852 | INFOPLIST_FILE = Configs/Eventually.plist; 853 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 854 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 855 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-tvOS"; 856 | PRODUCT_NAME = Eventually; 857 | SDKROOT = appletvos; 858 | SKIP_INSTALL = YES; 859 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 860 | SWIFT_VERSION = 3.0; 861 | TARGETED_DEVICE_FAMILY = 3; 862 | TVOS_DEPLOYMENT_TARGET = 9.0; 863 | }; 864 | name = Release; 865 | }; 866 | 52D6DA211BF000BD002C0205 /* Debug */ = { 867 | isa = XCBuildConfiguration; 868 | buildSettings = { 869 | APPLICATION_EXTENSION_API_ONLY = YES; 870 | CODE_SIGN_IDENTITY = "-"; 871 | COMBINE_HIDPI_IMAGES = YES; 872 | DEFINES_MODULE = YES; 873 | DYLIB_COMPATIBILITY_VERSION = 1; 874 | DYLIB_CURRENT_VERSION = 1; 875 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 876 | FRAMEWORK_VERSION = A; 877 | INFOPLIST_FILE = Configs/Eventually.plist; 878 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 879 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 880 | MACOSX_DEPLOYMENT_TARGET = 10.10; 881 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-macOS"; 882 | PRODUCT_NAME = Eventually; 883 | SDKROOT = macosx; 884 | SKIP_INSTALL = YES; 885 | SWIFT_VERSION = 3.0; 886 | }; 887 | name = Debug; 888 | }; 889 | 52D6DA221BF000BD002C0205 /* Release */ = { 890 | isa = XCBuildConfiguration; 891 | buildSettings = { 892 | APPLICATION_EXTENSION_API_ONLY = YES; 893 | CODE_SIGN_IDENTITY = "-"; 894 | COMBINE_HIDPI_IMAGES = YES; 895 | DEFINES_MODULE = YES; 896 | DYLIB_COMPATIBILITY_VERSION = 1; 897 | DYLIB_CURRENT_VERSION = 1; 898 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 899 | FRAMEWORK_VERSION = A; 900 | INFOPLIST_FILE = Configs/Eventually.plist; 901 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 902 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 903 | MACOSX_DEPLOYMENT_TARGET = 10.10; 904 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-macOS"; 905 | PRODUCT_NAME = Eventually; 906 | SDKROOT = macosx; 907 | SKIP_INSTALL = YES; 908 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 909 | SWIFT_VERSION = 3.0; 910 | }; 911 | name = Release; 912 | }; 913 | DD7502831C68FCFC006590AF /* Debug */ = { 914 | isa = XCBuildConfiguration; 915 | buildSettings = { 916 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 917 | CODE_SIGN_IDENTITY = "-"; 918 | COMBINE_HIDPI_IMAGES = YES; 919 | INFOPLIST_FILE = Configs/EventuallyTests.plist; 920 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 921 | MACOSX_DEPLOYMENT_TARGET = 10.11; 922 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-macOS-Tests"; 923 | PRODUCT_NAME = "$(TARGET_NAME)"; 924 | SDKROOT = macosx; 925 | SWIFT_VERSION = 3.0; 926 | }; 927 | name = Debug; 928 | }; 929 | DD7502841C68FCFC006590AF /* Release */ = { 930 | isa = XCBuildConfiguration; 931 | buildSettings = { 932 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 933 | CODE_SIGN_IDENTITY = "-"; 934 | COMBINE_HIDPI_IMAGES = YES; 935 | INFOPLIST_FILE = Configs/EventuallyTests.plist; 936 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 937 | MACOSX_DEPLOYMENT_TARGET = 10.11; 938 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-macOS-Tests"; 939 | PRODUCT_NAME = "$(TARGET_NAME)"; 940 | SDKROOT = macosx; 941 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 942 | SWIFT_VERSION = 3.0; 943 | }; 944 | name = Release; 945 | }; 946 | DD7502961C690C7A006590AF /* Debug */ = { 947 | isa = XCBuildConfiguration; 948 | buildSettings = { 949 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 950 | INFOPLIST_FILE = Configs/EventuallyTests.plist; 951 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 952 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-tvOS-Tests"; 953 | PRODUCT_NAME = "$(TARGET_NAME)"; 954 | SDKROOT = appletvos; 955 | SWIFT_VERSION = 3.0; 956 | TVOS_DEPLOYMENT_TARGET = 9.1; 957 | }; 958 | name = Debug; 959 | }; 960 | DD7502971C690C7A006590AF /* Release */ = { 961 | isa = XCBuildConfiguration; 962 | buildSettings = { 963 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 964 | INFOPLIST_FILE = Configs/EventuallyTests.plist; 965 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 966 | PRODUCT_BUNDLE_IDENTIFIER = "com.Eventually.Eventually-tvOS-Tests"; 967 | PRODUCT_NAME = "$(TARGET_NAME)"; 968 | SDKROOT = appletvos; 969 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 970 | SWIFT_VERSION = 3.0; 971 | TVOS_DEPLOYMENT_TARGET = 9.1; 972 | }; 973 | name = Release; 974 | }; 975 | /* End XCBuildConfiguration section */ 976 | 977 | /* Begin XCConfigurationList section */ 978 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "Eventually" */ = { 979 | isa = XCConfigurationList; 980 | buildConfigurations = ( 981 | 52D6D98E1BEFF229002C0205 /* Debug */, 982 | 52D6D98F1BEFF229002C0205 /* Release */, 983 | ); 984 | defaultConfigurationIsVisible = 0; 985 | defaultConfigurationName = Release; 986 | }; 987 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Eventually-iOS" */ = { 988 | isa = XCConfigurationList; 989 | buildConfigurations = ( 990 | 52D6D9911BEFF229002C0205 /* Debug */, 991 | 52D6D9921BEFF229002C0205 /* Release */, 992 | ); 993 | defaultConfigurationIsVisible = 0; 994 | defaultConfigurationName = Release; 995 | }; 996 | 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Eventually-iOS Tests" */ = { 997 | isa = XCConfigurationList; 998 | buildConfigurations = ( 999 | 52D6D9941BEFF229002C0205 /* Debug */, 1000 | 52D6D9951BEFF229002C0205 /* Release */, 1001 | ); 1002 | defaultConfigurationIsVisible = 0; 1003 | defaultConfigurationName = Release; 1004 | }; 1005 | 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "Eventually-watchOS" */ = { 1006 | isa = XCConfigurationList; 1007 | buildConfigurations = ( 1008 | 52D6D9E81BEFFF6E002C0205 /* Debug */, 1009 | 52D6D9E91BEFFF6E002C0205 /* Release */, 1010 | ); 1011 | defaultConfigurationIsVisible = 0; 1012 | defaultConfigurationName = Release; 1013 | }; 1014 | 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "Eventually-tvOS" */ = { 1015 | isa = XCConfigurationList; 1016 | buildConfigurations = ( 1017 | 52D6DA021BEFFFBE002C0205 /* Debug */, 1018 | 52D6DA031BEFFFBE002C0205 /* Release */, 1019 | ); 1020 | defaultConfigurationIsVisible = 0; 1021 | defaultConfigurationName = Release; 1022 | }; 1023 | 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "Eventually-macOS" */ = { 1024 | isa = XCConfigurationList; 1025 | buildConfigurations = ( 1026 | 52D6DA211BF000BD002C0205 /* Debug */, 1027 | 52D6DA221BF000BD002C0205 /* Release */, 1028 | ); 1029 | defaultConfigurationIsVisible = 0; 1030 | defaultConfigurationName = Release; 1031 | }; 1032 | DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "Eventually-macOS Tests" */ = { 1033 | isa = XCConfigurationList; 1034 | buildConfigurations = ( 1035 | DD7502831C68FCFC006590AF /* Debug */, 1036 | DD7502841C68FCFC006590AF /* Release */, 1037 | ); 1038 | defaultConfigurationIsVisible = 0; 1039 | defaultConfigurationName = Release; 1040 | }; 1041 | DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "Eventually-tvOS Tests" */ = { 1042 | isa = XCConfigurationList; 1043 | buildConfigurations = ( 1044 | DD7502961C690C7A006590AF /* Debug */, 1045 | DD7502971C690C7A006590AF /* Release */, 1046 | ); 1047 | defaultConfigurationIsVisible = 0; 1048 | defaultConfigurationName = Release; 1049 | }; 1050 | /* End XCConfigurationList section */ 1051 | }; 1052 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */; 1053 | } 1054 | --------------------------------------------------------------------------------