捕获的self会在dispatch_async

时间:2015-09-22 08:52:27

标签: ios objective-c automatic-ref-counting grand-central-dispatch

我在我的应用程序内部遇到EXC_BAD_ACCESS错误,根据我的理解,该实际上应该捕获涉及此内容的所有内容,因此无法在块中释放它。 (ARC已启用)

这是我的代码:

- (void)_perform_async_onqueue:(void (^)(void))task {
    dispatch_async(self.workerQueue, task);
}

- (void)cancel {
    [self _perform_async_onqueue:^{
        // operation is strongly retained by self.
        // operation is also retained by an operation queue.
        // within `cancel` the operation is released from the operation queue
        [self.operation cancel];
    }
}];

这在[self.operation cancel]内崩溃。 self.operationNSOperation的子类。操作的cancel方法详细说明:

- (void)cancel {
    [self willChangeValueForKey:@"isCancelled"];
    _cancelled = YES;
    [self didChangeValueForKey:@"isCancelled"];
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    _finished = YES;
    _executing = NO;
    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"]; // CRASH (debugger lists `self` [= the operation] as `nil` in this line
}

据我所知,第一个self应该保留在调度块中。由于selfstrong有一个operation引用,所以这也应该在内存中,直到块执行结束。这怎么会导致EXC_BAD_ACCESS崩溃?

3 个答案:

答案 0 :(得分:1)

编辑:

不要在你的NSOperation子类中实现cancel方法。请致电:

[self.operation cancel];

一个好的tuto here

答案 1 :(得分:0)

方法没有对自我的强烈引用。如果在调用方法时取消分配self,则由您自己完成。 (这就是为什么你在弱对象上调用方法时会收到警告的原因,因为在方法运行时对象可能会消失)。

你可以指定SomeClass *我自己= self;这将使自己保持活力直到方法结束。

你也可以实现你自己的dealloc(它只是自动调用[super dealloc])并设置一个断点来找出 self被解除分配时,更好地理解事物。

答案 2 :(得分:0)

我发现了这个问题:

事实证明,所述行为完全正常。问题是这里使用的NSOperation是一个自定义的异步操作,它以错误的方式实现了取消:如果取消之前的操作它已由{{ 1}}操作队列然后过度释放操作。这就是操作被解除分配的原因,即使仍有强大的引用应该保留它。

我会为此提交文件。