简体   繁体   English

NSFastEnumeration消息发送到已释放实例

[英]NSFastEnumeration message sent to deallocated instance

I am trying to implement the NSFastEnumeration protocol for a sqlite query. 我正在尝试为sqlite查询实现NSFastEnumeration协议。

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? 在“强大”数据集中的“ countByEnumeratingWithState”中进行迭代时,是否需要保存结果,以便将其保留?

IE: IE浏览器:

@property (nonatomic, strong) NSMutableArray *resultList;

Then inside the while loop: 然后在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;
}

EDIT : 编辑

A little more research reveals that maybe I can just use __autoreleasing: 更多研究表明,也许我可以使用__autoreleasing:

MyRow * __autoreleasing row = [self queryRow];

Without having to maintain a strong array of objects. 无需维护大量对象。 Is this the right solution? 这是正确的解决方案吗?

The fast enumeration protocol relies on the collection it is enumerating retaining its contained items. 快速枚举协议依赖于其枚举保留其包含项的集合。 The caller (the compiler) ensures that the collection is itself is retained during the enumeration. 调用者(编译器)确保在枚举期间保留集合本身。

The array used by countByEnumeratingWithState: contains __unsafe_unretained references. countByEnumeratingWithState:使用的数组包含__unsafe_unretained引用。 This is safe as the compiler retains the collection, the collection retains the items, and so the references in the array will remain valid. 这是安全的,因为编译器将保留该集合,该集合将保留项目,因此数组中的引用将保持有效。

At the language level an object reference returned by fast enumeration is unowned by the caller and must be retained if need, which is of course handled automatically by ARC. 在语言级别,调用者不拥有由快速枚举返回的对象引用,并且在需要时必须保留该对象引用,这当然是由ARC自动处理的。 This is no different to how items returned from any other collection (arrays, dictionaries, etc.) are handled. 这与处理任何其他集合(数组,字典等)返回的项目没有什么不同。

Now your "collection" is different, it does not contain items but obtains them from an SQL query on demand. 现在,您的“集合”有所不同,它不包含项目,而是从SQL查询中按需获取它们。 Those items are not owned by your "collection" and so are deallocated by ARC when there is no longer any strong references to them. 这些项目不归您的“收藏”所有,因此当不再有任何强引用时,ARC将对其进行重新分配。 Therefore the __unsafe_unretained references you store in fast enumerations C array really are unsafe - ARC deallocates what they reference. 因此,您存储在快速枚举C数组中的__unsafe_unretained引用确实是不安全的-ARC会释放它们引用的内容。

The solution is to add (ie instance variable) a standard collection, say an NSMutableArray , to your "collection". 解决方案是向您的“集合”添加(即实例变量)一个标准集合,例如NSMutableArray On each call to countByEnumeratingWithState: first empty out this collection, thereby discarding any references you hold to previous query results (which will also deallocated them if the calling code has not retained them), and then fill it with the query results that will be return for this call. 在对countByEnumeratingWithState:每次调用上countByEnumeratingWithState:首先清空此集合,从而丢弃对先前查询结果的所有引用(如果调用代码未保留它们,也将释放它们),然后用将要返回的查询结果填充它这个电话。

When your "collection" is itself finally deallocated by ARC any references to query results it still holds will also be discarded. 当您的“集合”最终由ARC最终重新分配时,所有仍保留的查询结果引用也将被丢弃。

It is worthwhile reading Apple's Enumeration Sample as its comments contain details of the memory management required to implement fast enumeration. 值得阅读Apple的Enumeration Sample,因为其注释包含实现快速枚举所需的内存管理的详细信息。

HTH 高温超导

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

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