paint-brush
OperationQueue + Mã không đồng bộ: Mọi thứ bạn cần biếttừ tác giả@bugorbn
532 lượt đọc
532 lượt đọc

OperationQueue + Mã không đồng bộ: Mọi thứ bạn cần biết

từ tác giả Boris Bugor5m2024/03/17
Read on Terminal Reader

dài quá đọc không nổi

Trong Swift, việc sử dụng hàng đợi hoạt động cho mã đồng bộ có vẻ giống như một địa ngục thuần túy bởi vì về cơ bản, mã được coi là hoàn thành nếu quá trình biên dịch mã của chúng hoàn tất. Vào thời điểm mã không đồng bộ được thực thi, bản thân `Thao tác` đã được hoàn thành. Để hiểu cách giải quyết vấn đề, bạn cần hiểu vòng đời của hoạt động diễn ra như thế nào.
featured image - OperationQueue + Mã không đồng bộ: Mọi thứ bạn cần biết
Boris Bugor HackerNoon profile picture

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 Twitter Nếu bạn có câu hỏi nào. Ngoài ra, bạn luôn có thể mua cho tôi một ly cà phê .


Cũng được xuất bản ở đây