【问题标题】:va_args() causing EXC_BAD_ACCESSva_args() 导致 EXC_BAD_ACCESS
【发布时间】:2014-09-27 09:50:14
【问题描述】:

我在使用 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 的包装器,它本身就是 SQLite 的包装器。

【问题讨论】:

  • 为什么你认为你不应该使用“nil”作为终结者/哨兵?我不认为 va_arg 支持这种循环。
  • 请记住,您的解决方案虽然不错,但很脆弱。如果传递了额外的参数,它们将被默默地忽略。如果传递的参数太少,则应用程序可能会崩溃或更糟,它可以运行但数据错误。小心。

标签: ios objective-c sqlite fmdb variadic-functions


【解决方案1】:

您需要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 终止符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-27
    • 2016-11-19
    • 2012-10-02
    • 2011-04-14
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多