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

发布于 2024-12-23 01:01:54 字数 3620 浏览 5 评论 0原文

因此,我们尝试演示一个由 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

蓝眼泪 2024-12-30 01:01:54

看起来,当您传递 id 数组时,您的 bindSQL:arguments: 接受 va_list

因此,ARC不知道如何处理从id*va_list的转换。如果它在打开 ARC 之前起作用,那么只是您很幸运,目标机器上的某些内部表示相匹配。但即使没有 ARC,您也无法确定这一点,因为它可能会意外地给您带来一些严重的崩溃。

It seems that your bindSQL:arguments: accepts va_list while you are passing an array of id's, instead.

Therefore, ARC does not know how to deal with cast from id* to va_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.

冰雪梦之恋 2024-12-30 01:01:54

克雷格,

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

安德鲁

·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()

这段代码在 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:

@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

Now a standard C-function that calls the class:

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()

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文