繁体   English   中英

块内的弱引用

[英]Weak references inside a block

我正在使用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];

所以,我的问题是,让我们说当图像完成渲染并且该行返回时, Cell对象不再存在(它已被解除分配,可能是由于单元重用,这有点难以形式化)。 当我去访问[weakSelf setImageViewImage:] ,会导致EXC_BAD_ACCESS错误吗?

目前我正在试图追踪问题的原因,我认为这可能与此有关。

所以, __weak 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.
}];

如果你不使用weak,你就是在创建一个保留周期,但是一旦块完成执行,周期就会被打破。 我可能不会在这里使用弱者。

无论如何,你可以发送任何消息给nil ,它将被忽略。 因此,如果因为取消分配Cell对象而将weakSelf变量设置为nil ,则setImageViewImage:消息将无声地执行任何操作。 它不会崩溃。

既然你提到了单元重用,我假设你的CellUITableViewCell的子类。 在这种情况下,您的示例代码有一个严重的问题。 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];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM