diff --git a/Futures.xcodeproj/project.pbxproj b/Futures.xcodeproj/project.pbxproj index f561912..1a9b54f 100644 --- a/Futures.xcodeproj/project.pbxproj +++ b/Futures.xcodeproj/project.pbxproj @@ -129,12 +129,12 @@ B757AE7120B8A5BA00850F92 /* Sources */ = { isa = PBXGroup; children = ( - B757AE7220B8A5BA00850F92 /* Future */, + B757AE7220B8A5BA00850F92 /* Futures */, ); path = Sources; sourceTree = ""; }; - B757AE7220B8A5BA00850F92 /* Future */ = { + B757AE7220B8A5BA00850F92 /* Futures */ = { isa = PBXGroup; children = ( B757AE7320B8A5BA00850F92 /* FutureResult.swift */, @@ -144,7 +144,6 @@ B79FF3B620BC6E34001A625C /* AnyFuture.swift */, B768073720C6C02E00402ECB /* FutureProvider.swift */, ); - name = Future; path = Futures; sourceTree = ""; }; @@ -152,7 +151,7 @@ isa = PBXGroup; children = ( B757AE8320B8A5C700850F92 /* FutureTests */, - B757AE8520B8A5C700850F92 /* Future */, + B757AE8520B8A5C700850F92 /* Futures */, ); path = Framework; sourceTree = ""; @@ -166,30 +165,28 @@ path = FuturesTests; sourceTree = ""; }; - B757AE8520B8A5C700850F92 /* Future */ = { + B757AE8520B8A5C700850F92 /* Futures */ = { isa = PBXGroup; children = ( B757AE8620B8A5C700850F92 /* Futures.h */, B757AE8720B8A5C700850F92 /* Info.plist */, ); - name = Future; path = Futures; sourceTree = ""; }; B757AE8C20B8A60600850F92 /* Tests */ = { isa = PBXGroup; children = ( - B757AE8E20B8A60600850F92 /* FutureTests */, + B757AE8E20B8A60600850F92 /* FuturesTests */, ); path = Tests; sourceTree = ""; }; - B757AE8E20B8A60600850F92 /* FutureTests */ = { + B757AE8E20B8A60600850F92 /* FuturesTests */ = { isa = PBXGroup; children = ( B757AE8F20B8A60600850F92 /* FuturesTests.swift */, ); - name = FutureTests; path = FuturesTests; sourceTree = ""; }; diff --git a/Sources/Futures/Future.swift b/Sources/Futures/Future.swift index dcf0721..922840a 100644 --- a/Sources/Futures/Future.swift +++ b/Sources/Futures/Future.swift @@ -466,7 +466,7 @@ public extension Future { /// Note that the provided callback is called regardless of whether this future is fulfilled or rejected. /// The returned `Future` is fulfilled **only** if this and the provided future both are fullfilled. /// - /// In essence, the returned future will forward the result of this future, if the provided future + /// In short, the returned future will forward the result of this future, if the provided future /// is fulfilled. /// /// - Parameters: @@ -474,7 +474,7 @@ public extension Future { /// - initialResult: An initial result to begin the reduction. /// - callback: A callback that returns a `Future` to be deferred. /// - Returns: A future that will receive the eventual value. - func `defer`(on queue: DispatchQueue = .futures, callback: @escaping () -> Future) -> Future { + func always(on queue: DispatchQueue = .futures, callback: @escaping () -> Future) -> Future { let promise = Promise() whenResolved(on: queue) { result1 in @@ -497,6 +497,29 @@ public extension Future { return promise.future } + /// Returns a new `Future` that will resolve with the result of this `Future` **after** the provided callback + /// runs. + /// + /// Note that the provided callback is called regardless of whether this future is fulfilled or rejected. + /// + /// This method is useful for times you want to execute code at the end of a chain of operations, regarless + /// of whether successful or not. + /// + /// - Parameters: + /// - queue: Dispatch queue to observe on. + /// - callback: Callback to run. + /// - Returns: A future that will receive the eventual value. + func `defer`(on queue: DispatchQueue = .futures, callback: @escaping () -> Void) -> Future { + let promise = Promise() + + whenResolved(on: queue) { result in + callback() + promise.resolve(result) + } + + return promise.future + } + enum PollError: Error { case retryCountExceeded } @@ -507,14 +530,14 @@ public extension Future { /// is acceptable. /// /// - Parameters: - /// - dispatchQueue: Dispatch queue to poll on, + /// - queue: Dispatch queue to poll on, /// - future: Future used as the polling function. /// - interval: Time to wait between invoking subsequent futures. /// - retryCount: maxRetryCount Maximum number of times to invoke the supplied future /// - finished: Handler to invoke, resolving whether the result of the given promise is acceptable /// - Returns: A future that will receive the eventual value. static func poll( - on dispatchQueue: DispatchQueue = .futures, + on queue: DispatchQueue = .futures, future: @escaping @autoclosure () -> Future, interval: TimeInterval, maxRetryCount: Int, @@ -534,7 +557,7 @@ public extension Future { if finished(value) { promise.fulfill(value) } else if numberOfRetries < maxRetryCount { - dispatchQueue.asyncAfter(deadline: .now() + (numberOfRetries < 1 ? 0 : interval)) { + queue.asyncAfter(deadline: .now() + (numberOfRetries < 1 ? 0 : interval)) { poll() } } else { @@ -551,6 +574,28 @@ public extension Future { return promise.future } + + /// Returns a new Future, effectively discarding the result of the caller. + /// + /// This method is useful when the value of a future is of no consequence. + /// + /// - Parameter queue: Dispatch queue to discard on. + /// - Returns: A future that will receive the eventual value. + @discardableResult + func discard(on queue: DispatchQueue = .futures) -> Future { + + let promise = Promise() + + whenFulfilled(on: queue) { _ in + promise.fulfill() + } + + whenRejected { error in + promise.reject(error) + } + + return promise.future + } } public extension Future {