在使用va_args(iOS 7、Xcode 5.1.1、ARC开启)时,我遇到了EXC_BAD_ACCESS错误:
// ...
int val = sqlIntQuery(@"format_string", @"arg1"); // <-- does not work
int val = sqlIntQuery(@"format_string", @"arg1", nil); // <-- this works
// ...
- (int)sqlIntQuery:(NSString *)format, ...
{
va_list args;
va_start(args,format);
__unsafe_unretained id eachObject;
NSMutableArray *arguments = [NSMutableArray array];
while ( (eachObject = va_arg(args, id)) != nil ) { // <-- crash on 2nd loop
[arguments addObject:eachObject];
}
va_end(args);
// ... process 'arguments'
return 5; // return a computed intValue
}
如果我在循环的结尾加上“break;”(因为我只有一个参数),或者将“nil”作为最后一个参数添加,就不会崩溃,但我认为我不应该添加“nil”。我怀疑这是ARC问题,但我正在使用__unsafe_unretained,就像其他人在SO上建议的那样。(有没有办法将“nil”推入args中?)
是什么导致第二次循环失败?
编辑于8月6日:我的解决方案:
当maddy提到“格式说明符的数量”时,他所接受的解决方案将我引向了正确的方向。我的格式参数对于每个参数都有一个“?”占位符,所以我只需计算它们的数量。因此,记录如下:
- (int)sqlIntQuery:(NSString *)format, ...
{
int numberOfArgs = [format componentsSeparatedByString:@"?"].count - 1; // <<-- this solved my problem
va_list args;
va_start(args,format);
NSMutableArray *arguments = [NSMutableArray array];
while ( numberOfArgs-- ) {
id eachObject = va_arg(args, id);
[arguments addObject:eachObject];
}
va_end(args);
FMResultSet *rs = [db executeQuery:format withArgumentsInArray:arguments];
[rs next];
int ret = [rs intForColumnIndex:0];
[rs close];
return ret;
}
这是一个双层包装。我的程序是对FMDB进行的封装,而FMDB本身则是对SQLite进行的封装。