Ở phần 1 của bài viết, mình đã giới thiệu về Operation là gì. Ở phần 2 của loạt bài về Operation, mình sẽ nói về Dependency trong Operation.
Nội dung bài viết:
- Operation Dependencies
- Passing Data using Dependencies
Operation Dependencies:
Operation cho phép bạn thiết lập các sự phụ thuộc lẫn nhau. Điều này mang lại 2 lợi ích:
- Giả sử operation 2 phụ thuộc vào operation 1. Khi đó operation 2 chỉ được thực hiện sau khi operation 1 đã hoàn thành.
- Cung cấp 1 cách để bạn truyền data giữa các operation.
class DownloadImage: Operation {
var index: Int
init(ind: Int) {
self.index = ind
}
override func main() {
// Download image task
print("Start downloading task \(index) at time: \(Date().timeIntervalSince1970)")
sleep(5)
print("Finish downloading task \(index) at time: \(Date().timeIntervalSince1970)")
}
}
let firstOperation = DownloadImage(ind: 1)
let secondOperation = DownloadImage(ind: 2)
//firstOperation.addDependency(secondOperation)
let operationQueue = OperationQueue()
operationQueue.addOperation(firstOperation)
operationQueue.addOperation(secondOperation)
Ở trên là đoạn code khởi tạo 2 operation bình thường, giữa chúng chưa có dependency. Chạy đoạn code trên và đây là kết quả thu được:
Giờ thì bỏ comment dòng code firstOperation.addDependency(secondOperation) và chạy thử:
Note: Bạn có thể tạo dependency cho 2 opeartion đang chạy ở 2 operation queue khác nhau.
Đây là 1 cách khá ngắn trong khi ở GCD bạn phải khai báo 1 dispatchGroup, sau đó gọi hàm enter(), leave(), notify(), … Tuy nhiên, cách làm này rất dễ gây ra deadlock.
Để remove 1 dependency, bạn chỉ cần gọi:
firstOperation.removeDependency(op: secondOperation)
Ở đoạn code mẫu ở trên, nếu bạn sửa đoạn code thành như dưới đây thì code của bạn sẽ bị deadlock và không chạy.
firstOperation.addDependency(secondOperation)
secondOperation.addDependency(firstOperation)
Note: Hãy vẽ sơ đồ ra 1 tờ giấy để luôn clear về flow của bạn, tránh bị deadlock.
Truyền data giữa các operation thông qua dependency:
class Calculate: Operation {
let firstNum: Int
let secondNum: Int
var sum: Int?
init(first: Int, second: Int) {
self.firstNum = first
self.secondNum = second
}
override func main() {
sum = firstNum + secondNum
}
}
class Display: Operation {
override func main() {
// 2
let sum = dependencies.compactMap{ ($0 as? Calculate)?.sum }.first
guard let unwrappedSum = sum else {
return
}
// 3
print("Sum = \(unwrappedSum)")
}
}
let calculateOperation = Calculate(first: 5, second: 10)
let displayOperation = Display()
// 1
displayOperation.addDependency(calculateOperation)
let operationQueue = OperationQueue()
// 4
operationQueue.addOperation(calculateOperation)
operationQueue.addOperation(displayOperation)
- Khởi tạo 2 operation, và set dependency để task Display chỉ chạy sau khi task Calculate hoàn thành.
- Hàm main() là hãm sẽ chạy khi 1 operation được chạy.
Ở đây, ta sẽ lấy ra list operations có dependency với DisplayOperation, chọn ra operation nào là Calculate và lấy ra sum. - Nếu sum khác nil thì hiển thị ra.
- Add các operation vào queue để chạy.
Kết quả hiển thị trên màn hình Console:
Dependency trong Operation là 1 trong những thứ giúp Operation vượt trội hơn so với GCD.
Ở phần tiếp, mình sẽ nói về Async Operation và xử lí cancel Opeartion.