如何从块中获取NSString?

时间:2012-02-16 07:22:24

标签: iphone return-value objective-c-blocks fmdb

我一直在尝试,但我只是没有得到很好的阻止。我正在使用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 个答案:

答案 0 :(得分:7)

看来你的问题归结为“如何从块内返回一个值回调用函数?”它实际上相当简单,只要块同步执行即可。只需使用__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);
});

答案 1 :(得分:4)

我认为你错过了同步和异步执行之间的区别。我不熟悉您使用的队列API,但我会说您插入到DB队列中的块不会立即同步执行。它在稍后的某个时间点异步执行,然后才会生成结果字符串。

您的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);
}];

另一种选择是在字符串可用时调用已知方法,请参阅Kevin的回答。