0

以下是我在基于 iOS 4(无 ARC)的 lynda iOS 培训课程中学到的代码段。

我打算在我的 Xcode 4.2 中实现相同的代码,它通过 iOS 5 SDK 打开了 ARC。它给了我这个错误:

错误:语义问题:将“__strong id *”发送到“__unsafe_unretained id **”类型的参数会更改指针的保留/释放属性”

- (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];
    }
}

** 真实案例伴随着整个函数的以下部分。**

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

我该如何解决这个问题?

4

2 回答 2

0

这个功能有很多问题。编译器错误的修复只是声明keysvalues使用__unsafe_unretained所有权限定符:

__unsafe_unretained id keys[dictSize];  // not used, just a side-effect of getObjects:andKeys
__unsafe_unretained id values[dictSize];

但是,强制转换(va_list)values是未定义的行为。不要这样做。

由于您根本不使用keys数组,因此最好执行以下操作:

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

    NSMutableArray * placeHoldersArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count; i++) {
        [placeHoldersArray addObject: @"?"];
    }

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

    [self bindSQL:[query UTF8String] arguments:[record allValues]];
    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];
    }
}

然后修改bindSQL:arguments:为采用 aNSArray *而不是 a va_list。如果您需要帮助,请向我们展示bindSQL:arguments:.

(但是,我认为没有记录allKeysallValues返回并行数组......)

于 2012-12-02T07:13:46.747 回答
0

为 const char 指针编辑:

- (NSNumber *) insertRow:(NSDictionary *) record {
    NSArray * placeHoldersArray = [NSArray array];
    const char * cStrings[record.count];
    NSArray * keys = [record allKeys];
    NSUInteger i=0;
    for (id key in keys) {
        id object = [record objectForKey:key];
        if ([object isKindOfClass:[NSString class]])
            cStrings[i++] = [(NSString*)object UTF8String];
        else
            @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Expected NSString" userInfo:nil];
        placeHoldersArray = [placeHoldersArray arrayByAddingObject: @"?"]; 
    }    
    NSString * query = [NSString stringWithFormat:@"insert into %@ (%@) values (%@)",
                            tableName,
                            [keys componentsJoinedByString:@","],
                            [placeHoldersArray componentsJoinedByString:@","]];

    [self bindSQL:[query UTF8String] arguments:(va_list)cStrings];
    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];
    }
}

在更新方法中,您应该了解 va_list 只是一组任意数量的参数。假定被调用的方法知道如何确定类型。这方面的一个例子是 NSLog。它使用格式字符串来确定未知数量的变量的类型,这些变量作为 va_list 传入,即逗号分隔值。因为您只有一个值,所以只需传入该值即可。我对 sqlite 是否需要 ac 字符串或在这种情况下是否需要一个整数持粗略态度。

于 2012-12-02T07:15:27.607 回答