我正在试图弄清楚如何让数据库提取在后台运行。以下是同一功能的前景和后台版本。前台版本有效。但在后台版本中,永远不会分配局部变量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;
}
答案 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。