0

以下は、iOS 4 (ARC なし) に基づく lynda iOS トレーニング コースで学んだコード セグメントです。

iOS 5 SDK で ARC がオンになっている Xcode 4.2 に同じコードを実装しようとしていました。それは私にこのエラーを与えました:

エラー: セマンティックな問題: タイプ '__unsafe_unretained id **' のパラメーターに '__strong 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

その機能には多くの間違いがあります。コンパイラ エラーの修正は、所有権修飾子keysを使用して宣言するだけです。values__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:を取るように変更します。ヘルプが必要な場合は、 のソース コードを見せてください。NSArray *va_listbindSQL:arguments:

(ただし、並列配列allKeysを返すことは文書化されていないと思います…)allValues

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

update メソッドでは、va_list は任意の数の引数の単なるグループであることを理解する必要があります。呼び出されるメソッドは、型を判別する方法を知っているものと想定されます。この例は、NSLog の場合です。フォーマット文字列を使用して、va_list として渡される不明な数の変数のタイプ、つまりコンマ区切りの値を決定します。値は 1 つしかないため、値を渡すだけです。sqlite が ac 文字列を必要とするかどうか、またはこの場合整数を取るかどうかについては大ざっぱです。

于 2012-12-02T07:15:27.607 に答える