在操作完成之前调用 completionBlock
completionBlock be called before the operation done
我这里有一些代码:
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let types: [FeedTimeline] = [.special, .pr, .pickup, .lastPost]
var operations: [Operation] = []
for type in types {
let operation = BlockOperation {
print("Working")
self.getArticles(of: type, page: 1, completion: { (articles) in
print("Fetched")
})
}
operation.completionBlock = {
print("Done")
}
queue.addOperation(operation)
在我 运行 上面的代码之后,我得到以下结果:
Working
Done
Working
Working
Done
Done
Working
Done
一段时间后,我得到了 4 次“Fetched”。这是为什么?如果 API 请求 (getArticles) 完成,如何使 completionBlock
仅 运行。
我想要的是:working
-> fetched
-> done
-> working
....等等
此行为的原因是一旦对 self.getArticles
的调用被执行,操作将继续执行(即退出),而不是在它完成之后。
解决此问题的一种方法是使用 dispatch groups。试试下面的代码:
let queue = OperationQueue()
let group = DispatchGroup()
queue.maxConcurrentOperationCount = 1
let types: [FeedTimeline] = [.special, .pr, .pickup, .lastPost]
var operations: [Operation] = []
for type in types {
let operation = BlockOperation {
group.enter()
print("Working")
self.getArticles(of: type, page: 1, completion: { (articles) in
print("Fetched")
group.leave()
})
group.wait(timeout: DispatchTime.distantFuture)
}
operation.completionBlock = {
print("Done")
}
queue.addOperation(operation)
在这种情况下,对 group.wait() 的调用将阻塞,直到对 group.enter() 的每个调用都与对 group.leave() 的调用相匹配,这意味着 BlockOperation 将等到对 getArticles 的调用完成。
注意需要保证getArticles一直执行回调,如果不执行(比如网络超时),操作块将永远挂起。
您需要使用 Operation
的子 class 并覆盖 isExecuting
和 isFinished
来告诉系统您的操作何时开始和何时结束。像这样:
class AsyncOperation: Operation {
override var isAsynchronous: Bool {
return true
}
private let _queue = DispatchQueue(label: "asyncOperationQueue", attributes: .concurrent)
private var _isExecuting: Bool = false
override var isExecuting: Bool {
set {
willChangeValue(forKey: "isExecuting")
_queue.async(flags: .barrier) {
self._isExecuting = newValue
}
didChangeValue(forKey: "isExecuting")
}
get {
return _isExecuting
}
}
var _isFinished: Bool = false
override var isFinished: Bool {
set {
willChangeValue(forKey: "isFinished")
_queue.async(flags: .barrier) {
self._isFinished = newValue
}
didChangeValue(forKey: "isFinished")
}
get {
return _isFinished
}
}
}
然后从这个新的 class 子class 你的操作。我想如果你想用操作和操作队列来阅读 this 会有所帮助。
我这里有一些代码:
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let types: [FeedTimeline] = [.special, .pr, .pickup, .lastPost]
var operations: [Operation] = []
for type in types {
let operation = BlockOperation {
print("Working")
self.getArticles(of: type, page: 1, completion: { (articles) in
print("Fetched")
})
}
operation.completionBlock = {
print("Done")
}
queue.addOperation(operation)
在我 运行 上面的代码之后,我得到以下结果:
Working
Done
Working
Working
Done
Done
Working
Done
一段时间后,我得到了 4 次“Fetched”。这是为什么?如果 API 请求 (getArticles) 完成,如何使 completionBlock
仅 运行。
我想要的是:working
-> fetched
-> done
-> working
....等等
此行为的原因是一旦对 self.getArticles
的调用被执行,操作将继续执行(即退出),而不是在它完成之后。
解决此问题的一种方法是使用 dispatch groups。试试下面的代码:
let queue = OperationQueue()
let group = DispatchGroup()
queue.maxConcurrentOperationCount = 1
let types: [FeedTimeline] = [.special, .pr, .pickup, .lastPost]
var operations: [Operation] = []
for type in types {
let operation = BlockOperation {
group.enter()
print("Working")
self.getArticles(of: type, page: 1, completion: { (articles) in
print("Fetched")
group.leave()
})
group.wait(timeout: DispatchTime.distantFuture)
}
operation.completionBlock = {
print("Done")
}
queue.addOperation(operation)
在这种情况下,对 group.wait() 的调用将阻塞,直到对 group.enter() 的每个调用都与对 group.leave() 的调用相匹配,这意味着 BlockOperation 将等到对 getArticles 的调用完成。
注意需要保证getArticles一直执行回调,如果不执行(比如网络超时),操作块将永远挂起。
您需要使用 Operation
的子 class 并覆盖 isExecuting
和 isFinished
来告诉系统您的操作何时开始和何时结束。像这样:
class AsyncOperation: Operation {
override var isAsynchronous: Bool {
return true
}
private let _queue = DispatchQueue(label: "asyncOperationQueue", attributes: .concurrent)
private var _isExecuting: Bool = false
override var isExecuting: Bool {
set {
willChangeValue(forKey: "isExecuting")
_queue.async(flags: .barrier) {
self._isExecuting = newValue
}
didChangeValue(forKey: "isExecuting")
}
get {
return _isExecuting
}
}
var _isFinished: Bool = false
override var isFinished: Bool {
set {
willChangeValue(forKey: "isFinished")
_queue.async(flags: .barrier) {
self._isFinished = newValue
}
didChangeValue(forKey: "isFinished")
}
get {
return _isFinished
}
}
}
然后从这个新的 class 子class 你的操作。我想如果你想用操作和操作队列来阅读 this 会有所帮助。