Trong Swift, việc sử dụng OperationQueue
cho mã không đồng bộ có vẻ giống như địa ngục vì về cơ bản, Operations
được coi là hoàn thành nếu quá trình biên dịch mã đồng bộ của chúng hoàn tất.
Nói cách khác, việc biên dịch ví dụ được mô tả bên dưới sẽ tạo ra thứ tự thực thi bị hỏng vì vào thời điểm mã không đồng bộ được thực thi, bản thân Operation
đã được hoàn thành.
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") }
Mã này sẽ in:
First sync operation complete Second sync operation complete First async operation complete Second async operation complete
Tuy nhiên, có một cách để phá vỡ những hạn chế này. Để hiểu cách giải quyết vấn đề, bạn cần hiểu cách hoạt động Operation
.
Bản thân Operation
có bốn cờ mà bạn có thể theo dõi vòng đời của hoạt động:
isReady
- cho biết liệu Operation
có thể được thực hiện tại thời điểm này hay không.
isExecuting
—cho biết liệu một Operation
có đang được tiến hành hay không.
isFinished
—cho biết Operation
hiện đã hoàn thành hay chưa.
isCancelled
—cho biết liệu Operation
có bị hủy hay không.
Về lý thuyết, Operation
chuyển sang trạng thái isFinished
trước khi Operation
được thực thi không đồng bộ, vì vậy chúng ta cần phát triển một kỹ thuật để có thể điều khiển vòng đời của Operation
.
Khả năng này có thể được giải quyết bằng cách phân lớp Operation
và cũng bằng cách xác định lại các phương thức start
/ cancel
, cũng như tất cả các cờ mà vòng đời của hoạt động được xây dựng trên đó.
Đây là mã:
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) } } }
Lớp con mà chúng tôi nhận được từ Operation
là lớp cơ bản và cho phép chúng tôi hoàn thành nó một cách thủ công.
Để làm việc với các khối hoàn thành, bạn nên tạo một lớp con khác. Tuy nhiên, đây sẽ không phải là lớp con của Operation
mà là của 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?>? }
Lớp con này sẽ cho phép chúng ta chuyển một bao đóng tới Operation
, sau đó Operation
sẽ được hoàn thành.
Hãy thử loại hoạt động này trong thực tế:
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") } )
Kết quả là chúng tôi đã có thể đạt được việc thực thi đồng bộ Operations
:
First sync operation complete First async operation complete Second sync operation complete Second async operation complete
Đừng ngần ngại liên hệ với tôi trên
Cũng được xuất bản ở đây