Sno*_*man 11 iphone objective-c ios
我正在使用NSOperationQueue
并排队NSOperationBlocks
.现在,块具有对块中任何实例的强引用,并且调用对象也对块具有强大的保持,因此建议执行如下操作:
__weak Cell *weakSelf = self;
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
UIImage *image = /* render some image */
/* what if by the time I get here self no longer exists? */
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[weakSelf setImageViewImage:image];
}];
}];
[self.renderQueue addOperation:op];
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是,让我们说当图像完成渲染并且该行返回时,该Cell
对象不再存在(它已被解除分配,可能是由于单元重用,这有点难以形式化).当我去访问时[weakSelf setImageViewImage:]
,会导致EXC_BAD_ACCESS
错误吗?
目前我正在试图追踪问题的原因,我认为这可能与此有关.
Jon*_*ing 18
所以,__weak
是一个零弱的参考.这意味着在您的操作期间,self
可能确实已经解除分配,但是对它的所有弱引用(即weakSelf
)都将被清零.这意味着[weakSelf setImageViewImage:image]
只是发送消息nil
,这是安全的; 或者,至少,它不应该导致EXC_BAD_ACCESS
.(顺便说一句,如果你有资格weakSelf
的__unsafe_unretained
,你可能最终将消息发送到释放对象.)
因此,我怀疑向__weak
引用发送消息会导致崩溃.如果你想确保self
在你的操作期间存活下来,你可以在块范围内得到一个强有力的参考:
__weak Cell *weakSelf = self;
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
Cell *strongSelf = weakSelf; // object pointers are implicitly __strong
// strongSelf will survive the duration of this operation.
// carry on.
}];
Run Code Online (Sandbox Code Playgroud)
如果你不使用weak,你就是在创建一个保留周期,但是一旦块完成执行,周期就会被打破.我可能不会在这里使用弱者.
无论如何,你可以发送任何消息nil
,它将被忽略.因此,如果weakSelf
变量设置为nil
因为Cell
对象被释放,则setImageViewImage:
消息将默默地执行任何操作.它不会崩溃.
既然你提到了单元格重用,我认为你Cell
是一个子类UITableViewCell
.在这种情况下,您的示例代码有一个严重的问题. UITableViewCell
通常不会被取消分配.它们被放在单元重用队列中.因此,您的weakSelf
变量不会被置零,因为弱对象仅在对象实际解除分配时才会被置零.
当[weakSelf setImageViewImage:image]
行运行时,单元格可能已被重用以表示表格中的不同行,并且您将错误的图像放入单元格中.您应该将图像渲染代码从Cell
类中移出到表视图的数据源类中:
- (void)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Cell *cell = // get a cell...
[self startLoadingImageForIndexPath:indexPath];
return cell;
}
- (void)startLoadingImageForIndexPath:(NSIndexPath *)indexPath {
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
UIImage *image = [self renderImageForIndexPath:indexPath];
dispatch_async(dispatch_get_main_queue(), ^{
Cell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell setImageViewImage:image];
});
}];
[self.renderQueue addOperation:op];
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4863 次 |
最近记录: |