如何修复此代码中间接指针(在 ARC 下)的强制转换?
因此,我们尝试演示一个由 Lynda.com 提供的实现 NSFastEnumeration 的 SQLite 示例。将其转换为 ARC 对我来说是一个问题,因为我无法修复错误
Cast of an indirect pointer to an Objective-C pointer to 'va_list' (aka char *) is disallowed with ARC.
It is pointing to this line and the va_list cast
[self bindSQL:[query UTF8String] arguments:(va_list)values];
which is in this function where 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];
}
}
So we're trying to walkthru a SQLite example which implements NSFastEnumeration, provided by Lynda.com. Converting it to ARC has been an issue for me as I have been unable to fix the error
Cast of an indirect pointer to an Objective-C pointer to 'va_list' (aka char *) is disallowed with ARC.
It is pointing to this line and the va_list
cast
[self bindSQL:[query UTF8String] arguments:(va_list)values];
which is in this function where values
is defined (__unsafe_unretained
was added to fix some other error)
- (NSNumber *) insertRow:(NSDictionary *) record
{
int dictSize = [record count];
__unsafe_unretained id values[dictSize];
The implementation of bindSQL is
- (void) bindSQL:(const char *) cQuery arguments:(va_list)args
How is this corrected?
Thanks for the interest guys. As requested here is the original bindSQL function and the calling insertRow function
- (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];
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看起来,当您传递
id
数组时,您的bindSQL:arguments:
接受va_list
。因此,ARC不知道如何处理从
id*
到va_list
的转换。如果它在打开 ARC 之前起作用,那么只是您很幸运,目标机器上的某些内部表示相匹配。但即使没有 ARC,您也无法确定这一点,因为它可能会意外地给您带来一些严重的崩溃。It seems that your
bindSQL:arguments:
acceptsva_list
while you are passing an array ofid
's, instead.Therefore, ARC does not know how to deal with cast from
id*
tova_list
. If it worked before turning on ARC, it was just you being lucky that some internal representation at your target machine matched. But you cannot be sure of it even without ARC as it can start giving you, unexpectedly, some nasty crashes.克雷格,
你为什么要使用 va_list?当您从列表中拉出每个单独的项目时,您可以轻松地将数据保留在 NSDictionary 中,然后通过应用于 -allValues 数组的 -objectAtIndex: 来拉出它们。那么你就完全避免了这个问题。
安德鲁
·P.S.不要与框架或运行时对抗。你会感到沮丧并且会失败。
克雷格,
我不确定你的代码有什么问题,但我有足够的兴趣编写一个可以编译的示例。我希望这可以帮助您解决问题。我的示例是 va_list 在日志记录示例中的传统应用。 (这段代码是从我的更复杂的日志宏中提取的。因此它主要测试语言并且不做任何新颖的事情。)
首先,类:
现在是调用该类的标准 C 函数:
这段代码在 Xcode 中编译得很好v4.2.1 使用 clang v3。
请注意,此本机 C 类型没有
__bridge
或任何其他 ARC 类型限定符。因此,我不知道你的代码有什么问题。 (坦率地说,您没有给我们足够的代码来真正帮助您解决问题。)总之,
va_list
与 ARC 兼容。它是独立于ARC类型的。安德鲁
Craig,
Why are you using a va_list at all? As you pull each individual item out of the list, you could easily just leave the data in the NSDictionary and pull them out with an -objectAtIndex: applied to the -allValues array. Then you've just avoided this problem altogether.
Andrew
P.S. Don't fight the framework or runtime. You'll be frustrated and will lose.
Craig,
I'm not sure what is wrong with your code but I was interested enough to write an example that does compile. I hope this helps you figure your problem out. My example is a traditional application of a va_list in a logging example. (This code was extracted from my more complex logging macros. Hence it primarily tests the language and doesn't do anything novel.)
First, the class:
Now a standard C-function that calls the class:
This code compiles just fine in Xcode v4.2.1 using clang v3.
Notice that there are no
__bridge
or any other ARC type qualifiers for this native C-type. Hence, I don't know what is wrong with your code. (Frankly, you didn't give us enough code to really help you solve your problem.)In conclusion, a
va_list
is compatible with ARC. It is an independent of ARC type.Andrew