1

我试图弄清楚如何让数据库获取在后台运行。下面是同一功能的前台和后台版本。前台版本有效。但是在后台版本中,局部变量 retval 永远不会被分配。在 pageInfoForPageKey 函数中放置一个断点告诉我该函数永远不会被调用。

块内是否可以使用 self ?

//foreground version
- (PageInfo*)objectAtIndex:(NSInteger)idx
{
    return [[self dataController] pageInfoForPageKey:[[[self pageIDs] objectAtIndex:idx] integerValue]];
}

//background version
- (PageInfo*)objectAtIndex:(NSInteger)idx
{
    __block PageInfo* retval = nil;
    __block NSInteger pageID = [[[self pageIDs] objectAtIndex:idx] integerValue];

    dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(aQueue, ^{
        retval = [[self dataController] pageInfoForPageKey:pageID];
    });

    return retval;
}
4

1 回答 1

7

通过使用dispatch_async,您是在告诉系统您希望它很快运行您的块,并且您不想在返回之前等待您的块完成(甚至开始)dispatch_async。这就是异步的定义。这就是“在后台”的定义。

系统正在按照您的要求进行操作:它正在安排您的块运行,然后在块运行之前立即返回。所以该块没有设置retval在你之前return retval,因为该块还没有运行。

如果您想在后台运行数据库获取,您需要更改您的 API 以retval在块运行后稍后传递回(给需要它的人)。一种方法是将完成块作为消息参数传递。这是在后台执行提取的常见模式。例如,查看+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:].

你可以这样做:

- (void)fetchObjectAtIndex:(NSIndex)idx completion:(void (^)(PageInfo *))block {
    block = [block copy]; // unnecessary but harmless if using ARC
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSInteger pageKey = [[[self pageIDs] objectAtIndex:idx] integerValue];
        PageInfo* pageInfo = [[self dataController] pageInfoForPageKey:pageKey];
        dispatch_async(dispatch_get_main_queue(), ^{
            block(pageInfo);
        });
    });
}

然后你需要改变调用者objectAtIndex:来使用这个新的 API。

于 2013-05-02T21:54:50.670 回答