jem*_*ons 49 nsoperation nsoperationqueue objective-c-blocks
我有一个长时间运行的循环,我想在后台运行一个NSOperation
.我想用一个块:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
while(/* not canceled*/){
//do something...
}
}];
Run Code Online (Sandbox Code Playgroud)
问题是,如何检查它是否被取消.该块不带任何参数,并且operation
在块被捕获时为零.有没有办法取消块操作?
jem*_*ons 69
卫生署.亲爱的Google未来:当然,operation
当由块复制为零,但它不具有被复制.它可以__block
像这样限定:
//THIS MIGHT LEAK! See the update below.
__block NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
while( ! [operation isCancelled]){
//do something...
}
}];
Run Code Online (Sandbox Code Playgroud)
更新:
进一步冥想后,我发现这将在ARC下创建一个保留周期.在ARC中,我相信__block
存储是保留的.如果是这样,我们就遇到了麻烦,因为它NSBlockOperation
也保留了对传入块的强引用,现在它对操作有很强的参考作用,它对传入的块有强烈的引用,其中......
它不太优雅,但使用明确的弱引用应该打破循环:
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakOperation = operation;
[operation addExecutionBlock:^{
while( ! [weakOperation isCancelled]){
//do something...
}
}];
Run Code Online (Sandbox Code Playgroud)
任何有更优雅解决方案想法的人,请评论!
Rob*_*ert 45
加强jemmons的回答. WWDC 2012会议211 - 构建Concurent用户界面(33分钟)
NSOperationQueue* myQueue = [[NSOperationQueue alloc] init];
NSBlockOperation* myOp = [[NSBlockOperation alloc] init];
// Make a weak reference to avoid a retain cycle
__weak NSBlockOperation* myWeakOp = myOp;
[myOp addExecutionBlock:^{
for (int i = 0; i < 10000; i++) {
if ([myWeakOp isCancelled]) break;
precessData(i);
}
}];
[myQueue addOperation:myOp];
Run Code Online (Sandbox Code Playgroud)
使用Swift 4,您可以创建一个可取消BlockOperation
的addExecutionBlock(_:)
.addExecutionBlock(_:)
有以下声明:
func addExecutionBlock(_ block: @escaping () -> Void)
Run Code Online (Sandbox Code Playgroud)
将指定的块添加到接收器要执行的块列表中.
以下示例显示了如何实现addExecutionBlock(_:)
:
let blockOperation = BlockOperation()
blockOperation.addExecutionBlock({ [unowned blockOperation] in
for i in 0 ..< 10000 {
if blockOperation.isCancelled {
print("Cancelled")
return // or break
}
print(i)
}
})
Run Code Online (Sandbox Code Playgroud)
请注意,为了防止BlockOperation
实例与其执行块之间的保留周期,您必须在执行块内使用带有weak
或unowned
引用的捕获列表blockOperation
.
以下Playground代码显示如何检查BlockOperation
子类实例与其执行块之间没有保留周期:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class TestBlockOperation: BlockOperation {
deinit {
print("No retain cycle")
}
}
do {
let queue = OperationQueue()
let blockOperation = TestBlockOperation()
blockOperation.addExecutionBlock({ [unowned blockOperation] in
for i in 0 ..< 10000 {
if blockOperation.isCancelled {
print("Cancelled")
return // or break
}
print(i)
}
})
queue.addOperation(blockOperation)
Thread.sleep(forTimeInterval: 0.5)
blockOperation.cancel()
}
Run Code Online (Sandbox Code Playgroud)
这打印:
0
1
2
3
...
Cancelled
No retain cycle
Run Code Online (Sandbox Code Playgroud)