如何使用调度队列来运行函数

时间:2013-05-02 21:40:45

标签: objective-c grand-central-dispatch

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

街区内是否可以使用?

//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;
}

1 个答案:

答案 0 :(得分: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。