0

I am trying to implement the NSFastEnumeration protocol for a sqlite query.

I am running into: message sent to deallocated instance

- (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;
}

It seems as if the 'row' object is not being retained, so when it needs to be accessed in loop its already been deallocated.

Do I need to save the results when iterating in 'countByEnumeratingWithState' in a'strong' dataset, so that it is retained?

IE:

@property (nonatomic, strong) NSMutableArray *resultList;

Then inside the while loop:

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;
}

EDIT:

A little more research reveals that maybe I can just use __autoreleasing:

MyRow * __autoreleasing row = [self queryRow];

Without having to maintain a strong array of objects. Is this the right solution?

4

1 回答 1

1

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

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

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

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

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

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

值得阅读Apple 的枚举示例,因为它的注释包含实现快速枚举所需的内存管理的详细信息。

高温高压

于 2017-07-03T20:14:33.020 回答