首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >发送到已释放实例的NSFastEnumeration消息

发送到已释放实例的NSFastEnumeration消息
EN

Stack Overflow用户
提问于 2017-07-03 17:44:00
回答 1查看 72关注 0票数 0

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

我正在遇到:发送到解除分配实例的消息。

代码语言:javascript
复制
- (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;
}

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

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

IE:

代码语言:javascript
复制
@property (nonatomic, strong) NSMutableArray *resultList;

然后在while循环中:

代码语言:javascript
复制
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:

代码语言:javascript
复制
MyRow * __autoreleasing row = [self queryRow];

而不必维护一个强大的对象数组。这是正确的解决办法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-03 20:14:33

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

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

在语言级别,快速枚举返回的对象引用不属于调用方,必须在需要时保留,这当然是由ARC自动处理的。这与从任何其他集合(数组、字典等)返回的项没有什么不同。都被处理了。

现在您的“集合”不同了,它不包含项,而是根据需要从SQL查询中获得它们。这些物品不属于您的“收藏”,因此,在没有任何强有力的参考资料时,ARC就会取消它们的分配。因此,您存储在快速枚举C数组中的__unsafe_unretained引用确实是不安全的-- ARC释放它们引用的内容。

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

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

值得阅读苹果的枚举样本,因为它的注释包含实现快速枚举所需的内存管理的细节。

HTH

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44891397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档