我在我的应用程序中使用最新ARC版本的Bill Weinman的BWDB,它的工作就好了。然而在Release中它崩溃了。而且只有在真实设备上,在模拟器中才能正常工作。我已经尝试过来自Lynda.com的最新BWDB文件,它也崩溃了。
我发现当你枚举结果时,在forin循环中已经释放指向行的指针
for (NSDictionary *firstSpecies in [sql getFirstSpeciesName])
{
//firstSpecies is already released here
m_speciesName = [firstSpecies objectForKey:@"FirstSpeciesName"];
}
让我相信
的实施存在某种错误(NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len
或在enumRows变量中。
你知道如何解决这个问题吗?
答案 0 :(得分:1)
Bill Weinman的BWDB针对iOS 7进行了更新,这也可以解决问题。
RSSDB.m
iOS 7 SDK中的错误会阻止它在ARM上运行
// for (row in [self getQuery:@"SELECT id FROM feed ORDER BY LOWER(title)"]) {
// [idList addObject:row[@"id"]];
// }
iOS 7的解决方法
[self prepareQuery:@"SELECT id FROM feed ORDER BY LOWER(title)"];
while ((row = [self getPreparedRow])) {
[idList addObject:row[@"id"]];
}
答案 1 :(得分:0)
__unsafe_unretained和__weak都会阻止对象的保留,但方式略有不同。对于__weak,指向对象的指针将在它指向的对象的释放时转换为nil,这是非常安全的行为。顾名思义,__ innafe_unretained将继续指向对象所在的内存,即使它已被释放。由于访问了已释放的对象,这可能导致崩溃。
在BWDB示例中,在枚举函数中有一行存储到实例变量 enumRows
- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len
{
if ((*enumRows = [self getPreparedRow]))
{
state->itemsPtr = enumRows;
state->state = 0; // not used, customarily set to zero
state->mutationsPtr = state->extra; // also not used, required by the interface
return 1;
} else {
return 0;
}
}
和 enumRows 定义为:
__unsafe_unretained NSDictionary * enumRows[1];
方法GetPreparedRow声明如下:
- (NSDictionary *) getPreparedRow
{
int retCode = sqlite3_step(m_statement);
if (retCode == SQLITE_DONE)
{
sqlite3_finalize(m_statement);
return nil;
}
else if (retCode == SQLITE_ROW)
{
int col_count = sqlite3_column_count(m_statement);
if (col_count >= 1)
{
NSMutableDictionary * dRow = [NSMutableDictionary dictionaryWithCapacity:1];
for(int i = 0; i < col_count; i++)
{
NSString * columnName = [NSString stringWithUTF8String:sqlite3_column_name(m_statement, i)];
[dRow setObject:[self columnValue:i] forKey:columnName];
}
return dRow;
}
}
else
{
NSLog(@"rowFromPreparedQuery: could not get row: %s", sqlite3_errmsg(m_database));
return nil;
}
return nil;
}
因此,从GetPreparedRow方法返回的基本上 NSDictiornay *存储在__unsafe_unretained实例变量 enumRows 中。当 GetPreparedRow 完成后, NSDictionary *被释放,因为它超出范围,但 enumRows 仍然指向此内存。因此可以枚举行,但每个当前行都指向无效的内存。
我不确定为什么这在Debug和Release / Simulator中有效,但可能是因为 enumRows 仍然指向有效内存,因此它不会被删除或覆盖。我写信给Bill Weinman,他说这只发生在最新版本的LLVM编译器上,只有最优化ON。如果你有兴趣在他修理时听到,请跟随他的facebook page。
与此同时,我通过将 enumRows 一个__strong所有权修改为我的代码,简单定义为:
NSDictionary * enumRows;
我改变了枚举函数只是为了设置一个__unsafe_unretained指针指向这个__strong enumRows 指针
- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len
{
if ((enumRows = [self getPreparedRow]))
{
__unsafe_unretained id row = enumRows;
state->itemsPtr = &row;
state->state = 0; // not used, customarily set to zero
state->mutationsPtr = state->extra; // also not used, required by the interface
return 1;
} else {
return 0;
}
}
答案 2 :(得分:0)
@DaNY
如果我定义
NSDictionary * enumRows;
然后
(NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained *)stackbuf count:(NSUInteger)len
{
if ((enumRows = [self getPreparedRow]))
{
__unsafe_unretained id row = enumRows;
state->itemsPtr = &row;
...
我得到1个警告和1个错误(在编译之前):
不兼容的指针类型初始化'__unsafe_unretained',表达式为'NSDictionary * __strong [1]
ARC
不允许隐式转换指向Objective-C指针的间接指针