我有一个NSOperation
子类,它从UITableView
运行异步操作。
我覆盖了正确的开始和结束方法,如下所示:
- (void)start
{
[self willChangeValueForKey:@"isExecuting"];
self.isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
if (self.isCancelled)
{
[self finish];
return;
}
}
- (void)finish
{
if (!_isExecuting)
{
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
}
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
我遇到的问题,如果我向下滚动表并删除一行,则会在操作中调用cancel
方法,但随着操作逐渐完成并且它进一步向下移动,它会崩溃第EXC_BAD_ACCESS
行
[self didChangeValueForKey:@"isFinished"];
错误
将代码粘贴到此处的代码非常复杂,但我想知道的是如何跟踪导致KVO消息崩溃的对象?
如果我在调试器中启用了僵尸对象,它根本不会崩溃而没有任何不起作用的警告。
如果我在try/catch
中包装KVO方法,它永远不会被抓住并且仍会崩溃。
我尝试在我的NSOperation
子类中覆盖KVO方法,但它们永远不会被调用:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
{
NSLog(@"%s - %@", __PRETTY_FUNCTION__, observer);
[super addObserver:observer forKeyPath:keyPath options:options context:context];
}
是否可以看到观察者是谁?
答案 0 :(得分:2)
评论和想法:
start
self.isExecuting = YES
不应该_isExecuting = YES;
?identifier
的NSString类型的属性,并为每个操作设置它。dealloc
方法并记录identifier
。finish
的{{1}}测试中,如果是,请立即返回。另一个想法是双重保留操作 - 将它们放在以isCancelled
为键的NSDictionary中,并查看是否有任何更改。
答案 1 :(得分:1)
我遇到了同样的问题。 发生这种情况是因为您在调用start方法之前为isFinished变量设置了值。
要解决此问题,您需要在取消方法中设置标志isCancelled = YES(且仅)。 然后在-start方法中检查取消状态。
如果操作在开始之前被取消,那么您应该已经设置了这些值:
self.executing = YES;
self.executing = NO;
self.finished = YES;
所有代码:
-(void)start
{
if ((self.ready == YES) && (self.executing == NO) && ((self.finished == NO)) // if Ready To Start State
{
self.ready = NO; self.executing = YES; self.finished = NO; // Setting Working State
[self receiveItemAtURL:self.url params:self.params
timeStoreExpire:self.storageTime
progress:self.operationProgressBlock
completion:self.operationCompletionBlock];
}else if ((self.ready == NO) && (self.cancelled == YES){ // If Cancelled State
self.executing = YES;
self.executing = NO;
self.finished = YES;
}
}
- (void) cancel
{
if ((self.ready == YES) && (self.executing == NO) && ((self.finished == NO)) { // If Working State
self.ready = NO; self.cancelled = YES; // Setting Cancelled State
}
else if ((self.ready == NO) && (self.executing == YES) && (self.finished == NO) || // If Working State
(self.ready == YES) && (self.executing == NO) && (self.finished == NO)) // If Suspend State
{
self.state = RXCOCancelled;
self.executing = YES;
self.executing = NO;
self.finished = YES;
}
}