因此,我们试图通过一个实现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];
}
}
答案 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类型。
安德鲁