2

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

4

6 回答 6

2

语言不提供(即标准库),但您当然可以自己动手或简单地使用诸如https://github.com/Thomvis/BrightFutures之类的库

于 2014-10-23T23:12:34.623 回答
2

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

然而,语言本身缺少这样的特性。

于 2014-10-23T23:18:17.507 回答
1

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

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

NSOperationQueue().addOperationWithBlock {
    // do background work
    NSOperationQueue.mainQueue().addOperationWithBlock {
        // back to main thread for follow up work
    }
}
于 2015-06-12T20:28:26.690 回答
0

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

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

于 2015-06-12T19:04:43.790 回答
0

我最终得到以下基于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() {
   }

}
于 2016-12-23T18:58:18.367 回答
0

【Java 未来与承诺】

Swift 的Combine 框架使用了这些结构

于 2021-02-28T17:39:13.253 回答