Как я могу исправить приведение косвенного указателя (под ARC) в этом коде? - PullRequest
2 голосов
/ 29 декабря 2011

Итак, мы пытаемся пройтись по примеру SQLite, который реализует NSFastEnumeration, предоставленный 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];
}

}

Ответы [ 2 ]

0 голосов
/ 29 декабря 2011

Кажется, что ваш bindSQL:arguments: принимает va_list, пока вы передаете массив id вместо

Поэтому ARC не знает, как обращаться с приведением из id*до va_list.Если это сработало до включения ARC, просто вам повезло, что какое-то внутреннее представление на вашей целевой машине соответствовало.Но вы не можете быть уверены в этом даже без ARC, так как он может неожиданно вызвать неприятные сбои.

0 голосов
/ 29 декабря 2011

Крейг,

Почему вы вообще используете va_list?Когда вы извлекаете каждый отдельный элемент из списка, вы можете просто оставить данные в NSDictionary и извлечь их с помощью -objectAtIndex:, примененного к массиву -allValues.Тогда вы просто полностью избежали этой проблемы.

Эндрю

PS Не боритесь с фреймворком или средой выполнения.Вы будете разочарованы и проиграете.

Крейг,

Я не уверен, что не так с вашим кодом, но я был достаточно заинтересован, чтобы написать пример, который компилирует.Я надеюсь, что это поможет вам понять вашу проблему.Мой пример - это традиционное применение 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.

Обратите внимание, что нет __bridge или любого другого типа ARCквалификаторы для этого нативного C-типа.Следовательно, я не знаю, что не так с вашим кодом.(Честно говоря, вы не дали нам достаточно кода, чтобы действительно помочь вам решить вашу проблему.)

В заключение, va_list совместим с ARC.Это не зависит от типа ARC.

Андрей

...