0

我正在尝试为sqlite查询实现NSFastEnumeration协议。发送到释放实例的NSFastEnumeration消息

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

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

看起来好像在“行”的对象没有被保留下来,所以当它需要在循环中访问其已被释放。

当我在'强'数据集中'countByEnumeratingWithState'中迭代时,是否需要保存结果,以便保留结果?

IE:

@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]; 

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

+1

你不应该命名方法'get ...'。命名约定在ARC中有意义。 – Sulthan

+0

@Sulthan,固定。仍然问题仍然存在...... – lostintranslation

回答

1

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

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

在语言层面,由快速枚举返回的对象引用由调用方取消,必要时可以保留,这当然是由ARC自动处理的。这与处理从其他集合(数组,字典等)返回的项目没有什么不同。

现在你的“集合”是不同的,它不包含项目,但需要从SQL查询中获取它们。这些项目不属于你的“集合”,因此当ARC不再有任何强烈的引用时,它们将被ARC重新分配。因此,您存储在快速枚举C数组中的__unsafe_unretained引用确实是不安全的 - ARC会分配它们引用的内容。

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

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

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

HTH

+0

确实有帮助并且合理。这是我在'IE'部分提出的。我也可以通过使用'__autoreleasing'标志来让它在没有实例变量的情况下工作。见编辑。这是一种可能性,或者只是运气? – lostintranslation

+0

是的,我小心避免提及'__autoreleasing',你抓住了我;-)使用'__autoreleasing'非常小心,它是针对特定用例(查找ARC和'NSError **')。确保你明白它在做什么(阅读Clang ARC文档)。我*并不是说它在这里不起作用,而是你需要自己弄清楚语义,以便你真正理解它们,否则你最终可能会在脚下开枪。你可以向你的问题添加你的*推理*为什么你认为'__autoreleasing'应该工作,然后看看别人是否为你确认。 – CRD

相关问题