使用va_args(iOS 7,Xcode 5.1.1,ARC on)时,我收到了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
}
如果我说“休息”;在循环结束时(因为我只有一个参数),或者添加“nil”作为最后一个参数,没有崩溃,但我认为我不应该添加“nil”。我怀疑是ARC问题,但我正在使用__unsafe_unretained,正如其他地方所建议的那样。 (有没有办法可以将“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的包装器,它本身就是SQLite的包装器。
答案 0 :(得分:7)
您需要nil
或其他方式来了解要抓取的参数数量。 va_list
无法知道何时停止。
stringWithFormat:
之类的东西不需要nil
,因为它根据格式说明符的数量确定了参数的数量(这就是为什么它们需要匹配或者你的代码繁荣的原因)。请注意NSDictionary dictionaryWithObjectsAndKeys:
等方法如何要求nil
终结符或UIAlertView initWithTitle...
需要nil
otherButtonTitles
参数的终结符。
您可以做的是使用以下NSString
方法:
- (int)sqlIntQuery:(NSString *)format, ... {
va_list args;
va_start(args, format);
NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
// do whatever
va_end(args);
return 5;
}
当然,这个解决方案假设你希望从format
和方法的变量参数构建一个字符串。
如果您确实需要填充数组,那么在调用nil
方法时,您需要传递sqlIntQuery
终止符。