【问题标题】:Are there anything similar to Java's "Future" in Swift?Swift 中有没有类似于 Java 的“未来”的东西?
【发布时间】:2014-12-19 18:23:25
【问题描述】:

Java 具有可以在新线程中运行任务的 Future 或 FutureTask。然后,将执行结果返回给原线程。 Swift 中是否有任何功能可以实现这一点?

【问题讨论】:

    标签: swift promise future promisekit


    【解决方案1】:

    您正在研究某种称为Futures and promises 的语言结构。您可以找到一些示例,例如:

    但是语言本身缺少这样的功能。

    【讨论】:

      【解决方案2】:

      语言不提供(即标准库),但您当然可以自行开发或直接使用诸如 https://github.com/Thomvis/BrightFutures 之类的库

      【讨论】:

      • @user2864740,换个说法,我指的是标准库。
      【解决方案3】:

      如果 Apple 确实在 Swift 中实现了 Futures 或 Promises,他们会这么说吗?毕竟,他们总是避免谈论未来的产品。 ;)

      无论如何,最初的问题似乎通常是关于异步工作的方法,不一定是专门用 Futures/Promises 样式模型来做这件事。因此,虽然其他答案中提到的第三方库非常适合该模型,但您也可以在没有该模型的情况下使用与 ObjC 相同的 iOS 和 OS X 内置 API 进行异步工作:dispatchNSOperation .例如:

      NSOperationQueue().addOperationWithBlock {
          // do background work
          NSOperationQueue.mainQueue().addOperationWithBlock {
              // back to main thread for follow up work
          }
      }
      

      【讨论】:

        【解决方案4】:

        现在也有FutureKit 类似于 BrightFuture,但合成更像 BFTask

        我应该提到Bolts BFTask,虽然它是用Objective-C 编写的,但它也是一个不错的候选者。 (现在在 Facebook iOS SDK 中使用)

        【讨论】:

          【解决方案5】:

          我最终得到了以下基于 OperationOperationQueue 类的解决方案(仅限 iOS SDK,Swift 3):

          简而言之:将代码包装成同步或异步操作。使用实用程序类链接操作。将操作添加到串行队列中。

          如果出现错误,无需取消当前操作,只需跳过实际代码即可。此外,异步执行块必须调用finalize 回调来通知操作队列完成。可选地,DispatchQueue 可以作为参数提供。代码块将在该队列上异步执行。

          fileprivate func publishProductOnWebsite(listing: Listing) {
                var resultSKU: String?
                var resultError: Swift.Error?
                let chain = OperationsChain{ isExecuting, finalize in
                   let task = ServerAPI.create(publishInfo: listing.publishInfo) { sku, error in
                      guard isExecuting() else {
                         return // We are canceled. Nothing to do.
                      }
                      if let error = error {
                         resultError = error
                      } else if let sku = sku {
                         resultSKU = sku // Arbitrary thread. But OK as this example for serial operation queue.
                      }
                      finalize() // This will finish asynchronous operation
                   }
                   task.resume()
                }
                chain.thenAsync(blockExecutionQueue: DispatchQueue.main) { _, finalize in
                   if let sku = resultSKU {
                      listing.sku = sku
                      DBStack.mainContext.saveIfHasChanges(savingParent: true) { error in
                         resultError = error
                         finalize()
                      }
                   } else {
                      finalize()
                   }
                }
                chain.thenSync(blockExecutionQueue: DispatchQueue.main) { [weak self] in
                   if let error = resultError {
                      self?.handleError(error) // Executed on Main thread.
                   } else {
                      self?.trackPublish()
                      self?.eventHandler?(.publishCompleted)
                   }
                }
                operationQueue.cancelAllOperations()
                operationQueue.addOperations(chain.operations, waitUntilFinished: false)
          }
          

          OperationsChain 类:将代码块包装到Operation 并将操作保存到维护依赖关系的operations 数组中。

          public class OperationsChain {
          
             public private(set) var operations = [Operation]()
          
             public init(blockExecutionQueue: DispatchQueue? = nil,
                         executionBlock: @escaping AsynchronousBlockOperation.WorkItemBlock) {
                let op = AsynchronousBlockOperation(blockExecutionQueue: blockExecutionQueue, executionBlock: executionBlock)
                operations.append(op)
             }
          
             public init(blockExecutionQueue: DispatchQueue? = nil,
                         executionBlock: @escaping SynchronousBlockOperation.WorkItemBlock) {
                let op = SynchronousBlockOperation(blockExecutionQueue: blockExecutionQueue, executionBlock: executionBlock)
                operations.append(op)
             }
          
             @discardableResult
             public func thenAsync(blockExecutionQueue: DispatchQueue? = nil,
                                   executionBlock: @escaping AsynchronousBlockOperation.WorkItemBlock) -> AsynchronousBlockOperation {
                let op = AsynchronousBlockOperation(blockExecutionQueue: blockExecutionQueue, executionBlock: executionBlock)
                if let lastOperation = operations.last {
                   op.addDependency(lastOperation)
                } else {
                   assertionFailure()
                }
                operations.append(op)
                return op
             }
          
             @discardableResult
             public func thenSync(blockExecutionQueue: DispatchQueue? = nil,
                                  executionBlock: @escaping SynchronousBlockOperation.WorkItemBlock) -> SynchronousBlockOperation {
                let op = SynchronousBlockOperation(blockExecutionQueue: blockExecutionQueue, executionBlock: executionBlock)
                if let lastOperation = operations.last {
                   op.addDependency(lastOperation)
                } else {
                   assertionFailure()
                }
                operations.append(op)
                return op
             }
          
          }
          

          SynchronousBlockOperationAsynchronousBlockOperation 类。

          public final class SynchronousBlockOperation: Operation {
          
             public typealias WorkItemBlock = (Void) -> Void
          
             fileprivate var executionBlock: WorkItemBlock?
             fileprivate var blockExecutionQueue: DispatchQueue?
          
             public init(blockExecutionQueue: DispatchQueue? = nil, executionBlock: @escaping SynchronousBlockOperation.WorkItemBlock) {
                self.blockExecutionQueue = blockExecutionQueue
                self.executionBlock = executionBlock
                super.init()
             }
          
             public override func main() {
                if let queue = blockExecutionQueue {
                   queue.async { [weak self] in
                      self?.executionBlock?()
                   }
                } else {
                   executionBlock?()
                }
             }
          }
          
          open class AsynchronousBlockOperation: AsynchronousOperation {
          
             public typealias FinaliseBlock = (Void) -> Void
             public typealias StatusBlock = (Void) -> Bool
             public typealias WorkItemBlock = (@escaping StatusBlock, @escaping FinaliseBlock) -> Void
          
             fileprivate var executionBlock: WorkItemBlock?
             fileprivate var blockExecutionQueue: DispatchQueue?
          
             public init(blockExecutionQueue: DispatchQueue? = nil, executionBlock: @escaping AsynchronousBlockOperation.WorkItemBlock) {
                self.blockExecutionQueue = blockExecutionQueue
                self.executionBlock = executionBlock
                super.init()
             }
          
             open override func onStart() {
                if let queue = blockExecutionQueue {
                   queue.async { [weak self] in
                      self?.executionBlock?({ return self?.isExecuting ?? false }) {
                         self?.finish()
                      }
                   }
                } else {
                   executionBlock?({ [weak self] in return self?.isExecuting ?? false }) { [weak self] in
                      self?.finish()
                   }
                }
             }
          }
          

          AsynchronousOperation 类:Operation 的可重用子类。

          open class AsynchronousOperation: Operation {
          
             fileprivate var lockOfProperties = NonRecursiveLock.makeDefaultLock()
             fileprivate var lockOfHandlers = NonRecursiveLock.makeDefaultLock()
          
             fileprivate var mFinished = false
             fileprivate var mExecuting = false    
          }
          
          extension AsynchronousOperation {
          
             public final override var isAsynchronous: Bool {
                return true
             }
          
             public final override var isExecuting: Bool {
                return lockOfProperties.synchronized { mExecuting }
             }
          
             public final override var isFinished: Bool {
                return lockOfProperties.synchronized { mFinished }
             }
          
          }
          
          extension AsynchronousOperation {
          
             public final override func start() {
                if isCancelled || isFinished || isExecuting {
                   return
                }
                willChangeValue(forKey: "isExecuting")
                lockOfProperties.synchronized { mExecuting = true }
                onStart()
                didChangeValue(forKey: "isExecuting")
             }
          
             public final override func cancel() {
                super.cancel()
                if isExecuting {
                   onCancel()
                   finish()
                } else {
                   onCancel()
                   lockOfProperties.synchronized {
                      mExecuting = false
                      mFinished = true
                   }
                }
             }
          
             public final func finish() {
                willChangeValue(forKey: "isExecuting")
                willChangeValue(forKey: "isFinished")
                lockOfProperties.synchronized {
                   mExecuting = false
                   mFinished = true
                }
                onFinish()
                didChangeValue(forKey: "isExecuting")
                didChangeValue(forKey: "isFinished")
             }
          
          }
          
          extension AsynchronousOperation {
          
             /// Subclasses must launch job here.
             ///
             /// **Note** called between willChangeValueForKey and didChangeValueForKey calls, but after property mExecuting is set.
             open func onStart() {
             }
          
             /// Subclasses must cancel job here.
             ///
             /// **Note** called immediately after calling super.cancel().
             open func onCancel() {
             }
          
             /// Subclasses must release job here.
             ///
             /// **Note** called between willChangeValueForKey and didChangeValueForKey calls,
             /// but after properties mExecuting and mFinished are set.
             open func onFinish() {
             }
          
          }
          

          【讨论】:

            【解决方案6】:

            [Java Future and Promise]

            Swift 的 Combine framework 使用这些结构

            【讨论】:

              猜你喜欢
              • 2023-03-13
              • 1970-01-01
              • 1970-01-01
              • 2016-03-16
              • 2011-01-20
              • 1970-01-01
              • 1970-01-01
              • 2011-02-28
              • 2011-02-26
              相关资源
              最近更新 更多