paint-brush
OperationQueue + 异步代码:您需要了解的一切by@bugorbn
488
488

OperationQueue + 异步代码:您需要了解的一切

Boris Bugor5m2024/03/17
Read on Terminal Reader

在 Swift 中,使用同步代码的操作队列可能看起来像纯粹的地狱,因为在幕后,如果代码的编译完成,则代码被认为是完整的。当异步代码执行时,“操作”本身已经完成。要了解如何解决问题,您需要了解操作的生命周期是如何工作的。
featured image - OperationQueue + 异步代码:您需要了解的一切
Boris Bugor HackerNoon profile picture

在 Swift 中,使用OperationQueue来处理异步代码可能看起来像是纯粹的地狱,因为在幕后,如果同步代码的编译完成, Operations被认为是完成的。


换句话说,编译下面描述的示例将输出损坏的执行顺序,因为在执行异步代码时, Operation本身已经完成。


 let operationQueue = OperationQueue() operationQueue.maxConcurrentOperationCount = 1 operationQueue.addOperation { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { print("First async operation complete") } print("First sync operation complete") } operationQueue.addOperation { DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { print("Second async operation complete") } print("Second sync operation complete") }


此代码将打印:


 First sync operation complete Second sync operation complete First async operation complete Second async operation complete


然而,有一种方法可以绕过这些限制。要了解如何解决问题,您需要了解Operation幕后工作原理。


Operation本身有四个标志,您可以通过它们跟踪操作的生命周期:


  • isReady表示此时是否可以执行该Operation


  • isExecuting — 指示Operation当前是否正在进行。


  • isFinished — 指示Operation当前是否已完成。


  • isCancelled — 指示Operation是否已取消。


理论上,在Operation本身异步执行之前, Operation会进入isFinished状态,因此我们需要开发一种技术来操纵Operation的生命周期。


这种可能性可以通过子类化Operation并重新定义start / cancel方法以及构建操作生命周期的所有标志来解决。


这是代码:


 public class AsyncOperation: Operation { // MARK: Open override open var isAsynchronous: Bool { true } override open var isReady: Bool { super.isReady && self.state == .ready } override open var isExecuting: Bool { self.state == .executing } override open var isFinished: Bool { self.state == .finished } override open func start() { if isCancelled { state = .finished return } main() state = .executing } override open func cancel() { super.cancel() state = .finished } // MARK: Public public enum State: String { case ready case executing case finished // MARK: Fileprivate fileprivate var keyPath: String { "is" + rawValue.capitalized } } public var state = State.ready { willSet { willChangeValue(forKey: newValue.keyPath) willChangeValue(forKey: state.keyPath) } didSet { didChangeValue(forKey: oldValue.keyPath) didChangeValue(forKey: state.keyPath) } } }


我们从Operation中收到的子类是基本的,允许我们强制手动完成它。


要使用完成块,您应该创建另一个子类。但是,这不是Operation的子类,而是AsyncOperation的子类。


 public typealias VoidClosure = () -> Void public typealias Closure<T> = (T) -> Void public class CompletionOperation: AsyncOperation { // MARK: Lifecycle public init(completeBlock: Closure<VoidClosure?>?) { self.completeBlock = completeBlock } // MARK: Public override public func main() { DispatchQueue.main.async { [weak self] in self?.completeBlock? { DispatchQueue.main.async { self?.state = .finished } } } } // MARK: Private private let completeBlock: Closure<VoidClosure?>? }


这个子类将允许我们将闭包传递给Operation ,之后Operation将完成。


让我们在实践中尝试一下这种类型的操作:


 let operationQueue = OperationQueue() operationQueue.maxConcurrentOperationCount = 1 operationQueue.addOperation( CompletionOperation { completion in DispatchQueue.main.asyncAfter(deadline: .now() + 1) { print("First async operation complete") completion?() } print("First sync operation complete") } ) operationQueue.addOperation( CompletionOperation { completion in DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { print("Second async operation complete") completion?() } print("Second sync operation complete") } )


结果,我们能够实现Operations的同步执行:


 First sync operation complete First async operation complete Second sync operation complete Second async operation complete


请随时与我联系推特如有任何问题。此外,您还可以随时给我买杯咖啡


也发布在这里