如何在此代码中修复间接指针(在ARC下)的强制转换?

时间:2011-12-28 20:16:58

标签: objective-c xcode sqlite automatic-ref-counting

因此,我们试图通过一个实现NSFastEnumeration的SQLite示例,由Lynda.com提供。将它转换为ARC一直是我的问题,因为我无法修复错误

Cast of an indirect pointer to an Objective-C pointer to 'va_list' (aka char *) is      disallowed with ARC.

它指向此行和va_list强制转换

[self bindSQL:[query UTF8String] arguments:(va_list)values];

在此函数中定义了values(添加__unsafe_unretained以修复其他错误)

- (NSNumber *) insertRow:(NSDictionary *) record 
{
    int dictSize = [record count];
    __unsafe_unretained id values[dictSize];

bindSQL的实现是

- (void) bindSQL:(const char *) cQuery arguments:(va_list)args

如何纠正?

感谢有兴趣的人。这里要求的是原始的bindSQL函数和调用insertRow函数

- (void) bindSQL:(const char *) cQuery arguments:(va_list)args {
// NSLog(@"%s: %s", __FUNCTION__, cQuery);
int param_count;

// preparing the query here allows SQLite to determine
// the number of required parameters
if (sqlite3_prepare_v2(database, cQuery, -1, &statement, NULL) != SQLITE_OK) {
    NSLog(@"bindSQL: could not prepare statement (%s)", sqlite3_errmsg(database));
    statement = NULL;
    return;
}

if ((param_count = sqlite3_bind_parameter_count(statement))) {
    for (int i = 0; i < param_count; i++) {
        id o = va_arg(args, id);

        // determine the type of the argument
        if (o == nil) {
            sqlite3_bind_null(statement, i + 1);
        } else if ([o respondsToSelector:@selector(objCType)]) {
            if (strchr("islISLB", *[o objCType])) { // integer
                sqlite3_bind_int(statement, i + 1, [o intValue]);
            } else if (strchr("fd", *[o objCType])) {   // double
                sqlite3_bind_double(statement, i + 1, [o doubleValue]);
            } else {    // unhandled types
                NSLog(@"bindSQL: Unhandled objCType: %s", [o objCType]);
                statement = NULL;
                return;
            }
        } else if ([o respondsToSelector:@selector(UTF8String)]) { // string
            sqlite3_bind_text(statement, i + 1, [o UTF8String], -1, SQLITE_TRANSIENT);
        } else {    // unhhandled type
            NSLog(@"bindSQL: Unhandled parameter type: %@", [o class]);
            statement = NULL;
            return;
        }
    }
}

va_end(args);
return;

}

- (NSNumber *) insertRow:(NSDictionary *) record {
// NSLog(@"%s", __FUNCTION__);
int dictSize = [record count];

// the values array is used as the argument list for bindSQL
id keys[dictSize];  // not used, just a side-effect of getObjects:andKeys
id values[dictSize];
[record getObjects:values andKeys:keys];    // convenient for the C array

// construct the query
NSMutableArray * placeHoldersArray = [NSMutableArray arrayWithCapacity:dictSize];
for (int i = 0; i < dictSize; i++)  // array of ? markers for placeholders in query
    [placeHoldersArray addObject: [NSString stringWithString:@"?"]];

NSString * query = [NSString stringWithFormat:@"insert into %@ (%@) values (%@)",
                    tableName,
                    [[record allKeys] componentsJoinedByString:@","],
                    [placeHoldersArray componentsJoinedByString:@","]];

[self bindSQL:[query UTF8String] arguments:(va_list)values];
sqlite3_step(statement);
if(sqlite3_finalize(statement) == SQLITE_OK) {
    return [self lastInsertId];
} else {
    NSLog(@"doQuery: sqlite3_finalize failed (%s)", sqlite3_errmsg(database));
    return [NSNumber numberWithInt:0];
}

}

2 个答案:

答案 0 :(得分:0)

当您传递bindSQL:arguments:数组时,va_list似乎接受id

因此,ARC不知道如何处理从id*va_list的演员表。如果它在开启ARC之前有效,那么只是你很幸运,你的目标机器上的一些内部表示匹配。但是即使没有ARC,你也无法确定它,因为它可以开始意外地给你一些令人讨厌的崩溃。

答案 1 :(得分:-1)

克雷格,

你为什么要使用va_list?当您从列表中提取每个单独的项目时,您可以轻松地将数据保留在NSDictionary中,并使用-objectAtIndex:将它们应用于-allValues数组。然后你完全避免了这个问题。

安德鲁

P.S。不要对抗框架或运行时。你会感到沮丧并且会失败。

克雷格,

我不确定你的代码有什么问题,但我有兴趣写一个编译的例子。我希望这可以帮助你解决问题。我的示例是日志示例中的va_list的传统应用程序。 (这段代码是从我更复杂的日志记录宏中提取的。因此它主要测试语言并且没有做任何新颖的事情。)

首先,班级:

@interface Macros

+ (void) testWithVAList: (va_list) vaList;
+ (void) callTestWithVAList: (va_list) vaList;

@end

@implementation Macros

+ (void) testWithVAList: (va_list) vaList {
} // -testWithVAList:

+ (void) callTestWithVAList: (va_list) vaList {

    [self testWithVAList: vaList];

} // -callTestWithVAList:

@end

现在是一个调用类的标准C函数:

void testLog(NSString *format, ...);
void testLog(NSString *format, ...) {

    va_list argp;
    va_start(argp, format);

    [Macros testWithVAList: argp];

    NSLogv(format, argp);

    va_end(argp);

} // testLog()

此代码使用clang v3在Xcode v4.2.1中编译得很好。

请注意,此本机C类型没有__bridge或任何其他ARC类型限定符。因此,我不知道您的代码有什么问题。 (坦率地说,你没有给我们足够的代码来帮助你解决问题。)

总之,va_list与ARC兼容。它独立于ARC类型。

安德鲁