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 수행할 수 있는지 여부를 나타냅니다.


  • isExecutingOperation 현재 진행 중인지 여부를 나타냅니다.


  • isFinishedOperation 현재 완료되었는지 여부를 나타냅니다.


  • isCancelled - Operation 취소되었는지 여부를 나타냅니다.


이론적으로 Operation 자체가 비동기적으로 실행되기 전에 OperationisFinished 상태에 진입하므로 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


주저하지 말고 저에게 연락주세요 트위터 만약 질문이 있다면. 또한 언제든지 가능합니다. 나에게 커피를 사다 .


여기에도 게시됨