2014-10-23 3 views

ответ

2

Вы смотрите в какой-то языковой конструкции называется Futures and promises. Вы можете найти некоторые примеры, как:

Однако язык сама пропускает такую ​​функцию.

2

Не предусмотрено языком (имея в виду стандартную библиотеку), но вы можете уверенно катиться самостоятельно или просто использовать библиотеку, такие как https://github.com/Thomvis/BrightFutures

+0

@ user2864740, перефразированный, я имел в виду стандартную библиотеку. –

0

Существует также теперь FutureKit Подобно BrightFuture, но делает композицию более как BFTask

И я должен упомянуть Bolts BFTask, что в то время как написано в Objective-C также является хорошим кандидатом. (И теперь используется внутри Facebook iOS SDK)

1

Если бы Apple реализовала фьючерсы или обещания в Swift, они бы так сказали? В конце концов, они всегда избегают говорить о продуктах Future. ;)

В любом случае, исходный вопрос, как правило, касается способов выполнения асинхронной работы, а не обязательно о том, как это сделать с помощью модели стиля Futures/Promises. Итак, в то время как сторонние библиотеки, упомянутые в других ответах, отлично подходят для этой модели, вы также можете выполнять асинхронную работу без этой модели, используя те же самые встроенные API OS X iOS &, которые вы можете использовать в ObjC: dispatch или NSOperation. Например:

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

я в конечном итоге следующим раствором (только IOS, SDK, Swift 3) на основе Operation и OperationQueue классов:

Вкратце: Обертывание кода в синхронном или асинхронном режиме. Цепочные операции с использованием служебного класса. Добавление операций в последовательную очередь.

В случае ошибки нет необходимости отменять текущую операцию, просто пропустите действительный код. Кроме того, асинхронные блоки выполнения должны вызывать обратный вызов 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 
    } 

} 

SynchronousBlockOperation и AsynchronousBlockOperation классы.

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() { 
    } 

}