ios - 发送到释放实例的 NSFastEnumeration 消息

标签 ios objective-c automatic-ref-counting nsfastenumeration

我正在尝试为 sqlite 查询实现 NSFastEnumeration 协议(protocol)。

我遇到了: 发送到释放实例的消息

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len {

    // First call
    if(state->state == 0) {
        state->mutationsPtr = &state->extra[0];
        state->state = 1;
        sqlite3_reset(self.statement);
    }

    state->itemsPtr = stackbuf;

    NSUInteger count = 0;
    while (count < len) {
        int result = sqlite3_step(self.statement);

        if (result == SQLITE_DONE) {
            break;
        }

        MyRow *row = [self queryRow];
        stackbuf[count] = row;
        count += 1;
    }

    return count;
}

-(MyRow *) queryRow {
    MyRow * row = // query sqlite for row
    return row;
}

似乎“行”对象没有被保留,所以当需要在循环中访问它时,它已经被释放了。

在“strong”数据集中的“countByEnumeratingWithState”中迭代时,是否需要保存结果以便保留?

即:

@property (nonatomic, strong) NSMutableArray *resultList;

然后在 while 循环中:

while (count < len) {
    int result = sqlite3_step(self.statement);

    if (result == SQLITE_DONE) {
        break;
    }

    MyRow *row = [self queryRow];
    [self.resultList addObject:row];  // throw into a strong array so its retained
    stackbuf[count] = row;
    count += 1;
}

编辑:

更多的研究表明,也许我可以使用 __autoreleasing:

MyRow * __autoreleasing row = [self queryRow];

无需维护强大的对象数组。这是正确的解决方案吗?

最佳答案

快速枚举协议(protocol)依赖于它正在枚举的集合保留其包含的项目。调用者(编译器)确保在枚举期间保留集合本身。

countByEnumeratingWithState: 使用的数组包含 __unsafe_unretained 引用。这是安全的,因为编译器会保留集合,集合会保留项目,因此数组中的引用将保持有效。

在语言级别,快速枚举返回的对象引用不为调用者所有,如果需要则必须保留,这当然由 ARC 自动处理。这与处理从任何其他集合(数组、字典等)返回的项目的方式没有什么不同。

现在您的“集合”不同了,它不包含项目,而是根据需要从 SQL 查询中获取项目。这些项目不属于您的“集合”,因此当不再对它们有任何强引用时,ARC 将对其进行释放。因此,您存储在快速枚举 C 数组中的 __unsafe_unretained 引用确实是不安全的 - ARC 会释放它们引用的内容。

解决方案是向您的“集合”添加(即实例变量)一个标准集合,例如 NSMutableArray。在每次调用 countByEnumeratingWithState: 时,首先清空该集合,从而丢弃您持有的对先前查询结果的任何引用(如果调用代码未保留它们,它们也会被释放),然后用将为此调用返回的查询结果。

当您的“集合”本身最终被 ARC 释放时,它仍然保留的任何对查询结果的引用也将被丢弃。

值得一读Apple's Enumeration Sample因为它的注释包含实现快速枚举所需的内存管理的详细信息。

HTH

关于ios - 发送到释放实例的 NSFastEnumeration 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44891397/

相关文章:

ios - 无法更改自定义 UITableViewCell 中 UILabel 的大小

ios - 等待进入 Controller ,直到 wifi 启用 IOS

swift - ARC(自动引用计数)实战

objective-c - 在 Objective-C 中传递 block

ios - Swift 4 中的视频动画

iphone - slider 在时间段内自动递增

ios - NSManagedObjectContext 无法删除其他上下文中的对象

ios - 从顶部(如下拉菜单)隐藏的动画 TableView

mysql - 在 iOs App 中使用 Mysql

objective-c - 弧: how do I dealloc at the end of object life cycle?