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

Dav*_*d U 1 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;
}
Run Code Online (Sandbox Code Playgroud)

rob*_*off 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);
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

然后,您需要更改调用者objectAtIndex:以使用此新API.

  • 顺便提一下,来自WWDC 2012的[Session 211 - 在iOS上构建并发用户界面](https://developer.apple.com/videos/wwdc/2012/?id=211)视频提供了一些在后台运行的好方法. (3认同)