Как мне получить NSString из блока? - PullRequest
2 голосов
/ 16 февраля 2012

Я действительно пытался, но я не очень хорошо получаю блоки.Я нахожусь в процессе использования FMDatabaseQueue , и я пытаюсь сделать очень простой запрос на основе очереди.Вот что у меня есть:

-(NSString *) getReferenceForPage:(NSInteger) page
{
    [queue inDatabase:^(FMDatabase *db) {
        FMResultSet *rs = [db executeQuery:@"SELECT ref_text FROM table WHERE page = ?",[NSNumber numberWithInteger:page]];
        if ([rs next]) {
            //this is where I get the string
        }
    }];
    return @""; //And this is where I need to return it, but I can't get it to work
}

Я не знаю, почему мне так трудно это понять, но мне нужно уметь что-то делать со строкой, которую я получаю из набора результатов.,Обычно я просто вернул бы это, но это не полетит здесь.Может кто-то пролить свет на это?

Спасибо

РЕДАКТИРОВАТЬ: я делаю вызовы для моего объекта доступа к БД в надежде вернуть конкретное значение.Многие из этих вызовов будут выполняться в фоновых потоках, поэтому я использую эту очередь базы данных для обеспечения безопасности потоков.Я обновил контекст, окружающий запрос sql, чтобы показать, что мне нужно сделать.

Ответы [ 2 ]

7 голосов
/ 16 февраля 2012

Кажется, ваш вопрос сводится к тому, «как вернуть значение из блока обратно в вызывающую функцию?»На самом деле это довольно просто, если блок выполняется синхронно.Просто используйте переменную __block и присвойте ей значение.

__block NSString *result = nil;
[queue inDatabase:^(FMDatabase *db) {
    // I'm assuming this is synchronous, because I'm not familiar with the API
    FMResultSet *rs = [db executeQuery:@"SELECT ref_text FROM table WHERE page = ?", [NSNumber numberWithInteger:page]];
    if ([rs next]) {
        result = [[rs acquireStringSomehow] retain];
    }
}];
return [result autorelease];

Обратите внимание, что сохранение заключается в том, что может быть пул автоматического освобождения, обернутый вокруг блока, и мы должны убедиться, что значение сохраняется (а затемможет автоматически высвобождать его вне блока).

Если вместо этого блок выполняется асинхронно, вы не сможете получить значение, возвращаемое из вызывающей функции.Если вам нужно обработать этот случай, то вам нужно передать значение обратно в соответствующий поток для последующей обработки, например,

NSString *str = [rs fetchStringSomehow];
dispatch_async(dispatch_get_main_queue(), ^{
    processString(str);
});
4 голосов
/ 16 февраля 2012

Я думаю, что вам не хватает разницы между синхронным и асинхронным выполнением.Я не знаком с API очереди, который вы используете, но я бы сказал, что блок, который вы вставляете в очередь БД, не выполняется сразу, синхронно.Он выполняется асинхронно, в некоторый более поздний момент времени, и только тогда у вас будет доступная результирующая строка.

У вас есть два варианта для вашего getReferenceForPage метода: сделать его тоже асинхронным или сделать его синхроннымблокировка, пока строка результата не станет доступной.Первый вариант проще и желательнее.Есть несколько способов реализовать это, один из них - передать блок для использования строки, когда она доступна:

typedef void (^StringConsumer)(NSString*);

-(void) getReferenceForPage: (NSInteger) page consumer: (StringConsumer) consumer
{
    [queue inDatabase:^(FMDatabase *db) {
        FMResultSet *rs = [db executeQuery:…];
        if ([rs next]) {
            if (consumer)
               consumer([db getResultString]);
        }
    }];
}

// and in calling code:
[self getReferenceForPage:1 consumer:^(NSString *reference) {
    NSLog(@"Got reference: %@", reference);
}];

Другой вариант - вызвать известный метод, когда строка доступна, см. Ответ Кевина.

...