ios - va_args() 导致 EXC_BAD_ACCESS

标签 ios objective-c sqlite fmdb variadic-functions

我在使用 va_args 时收到 EXC_BAD_ACCESS(iOS 7、Xcode 5.1.1、ARC 开启):

    // ...
    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”插入参数?)

是什么导致第二次循环失败?


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 的包装器。

最佳答案

您需要 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 和方法的可变参数构建一个字符串。

如果您确实需要填充数组,那么在调用 sqlIntQuery 方法时需要传递一个 nil 终止符。

关于ios - va_args() 导致 EXC_BAD_ACCESS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25126864/

相关文章:

ios - iPhone 6+ 启动图像大于原始分辨率?

iphone - RestKit - 向所有请求附加参数

objective-c - 从固定的 UIImageView 或按钮中拖出新的 UIImageView 对象

java - HikariCP 地址规范和文档

ios - iphone 上的 SQLite "near"语法错误

ios - View Controller Transition 动画 subview 位置

ios - Appdelegate 前台/后台/事件/非事件进程

ios - iOS Core Image Filters Exposure、Hue、Sepia、Temparature、Tint、Vignette 的值范围

android - 如何以编程方式向各种移动应用商店提交、发布和升级应用程序?

python - 从查询到 Python 脚本的 SQLite 输出