共享资源访问的GCD模式+ UI更新?

时间:2012-09-28 08:11:59

标签: iphone ios cocoa-touch ios5 ios6

人们!我正在我的应用程序中实现共享缓存。我们的想法是在后台从Web获取缓存数据,然后使用新检索的数据更新缓存和UI。诀窍当然是确保线程安全,因为主线程将持续使用缓存。我不想以任何方式修改缓存,而其他人可能正在使用它。

我的理解是,使用@synchronized锁定对共享资源的访问权限并不是ObjectiveC中最优雅的方法,因为它会捕获到内核,因此相当迟缓。我一直在阅读,使用GCD代替是一个很好的选择(让我们暂时忽略它的堂兄NSOperation),我想弄清楚我的情况会有什么好的模式。这是一些示例代码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// download the data in a background thread
dispatch_async(queue, ^{
    CacheData *data = [Downloader getLatestData];

    // use the downloaded data in the main thread
    dispatch_sync(dispatch_get_main_queue(), ^{
        [AppCache updateCache:data];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"CacheUpdated" object:nil];
    });
});
  1. 这实际上会做我认为它做的事情,如果是这样,这是处理这种情况的最干净的方法吗?有一个blog post与我所说的非常接近,但我也想和你仔细检查一下。
  2. 我在想,只要我只访问共享同一线程/队列上的共享资源(在我的情况下为main),并且只在主服务器上更新UI,那么我将有效地实现线程安全。这是对的吗?
  3. 谢谢!

2 个答案:

答案 0 :(得分:1)

如果你问100位开发人员是最优雅的方式,你将获得至少100个不同的答案(可能更多!)

我所做的,以及对我有用的是,让单身人士课程进行图像管理。我使用Core Data,并直接在商店中保存缩略图,但在Core Data中使用文件系统和URL来获取“大”文件。核心数据设置为使用新的基于块的接口,因此它可以在自己管理的私有线程上完成所有工作。

可能的图像URLS在主线程上注册了标记。其他类可以请求该标记的图像。如果图像不存在,则返回nil,但是此类设置fetchingFlag,使用与NSURLConnection耦合的并发NSOperation来获取图像,当它获取它时,它使用接收到的图像数据在其线程上向单例发送消息,并且获取该消息的方法使用'[moc performBlock:...]'(无等待)来处理它。

当图像最终添加到存储库时,moc将使用接收到的图像标记在主队列上调度通知。想要图像的类可以监听这个,当它们得到它时(在主线程上),然后他们可以再次向moc询问图像,这显然就在那里。

答案 1 :(得分:1)

是。 除了其他考虑因素之外,考虑使用私有调度队列,而不是将读/写工作分流到主线程上。

dispatch_queue_t readwritequeue;
readwritequeue = dispatch_queue_create("com.myApp.cacheAccessQueue", NULL);

然后更新您的AppCache类:

- (void)updateCache:(id)data {
 dispatch_sync(readwritequeue, ^{ ... code to set data ... });
}

- (id)fetchData:... {
 __block id data = nil;
 dispatch_sync(readwritequeue, ^{ data = ... code to fetch data ...});
 return data;
}

然后更新您的原始代码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// download the data in a background thread
dispatch_async(queue, ^{
    CacheData *data = [Downloader getLatestData];
    **[AppCache updateCache:data];**

    // use the downloaded data in the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:@"CacheUpdated" object:nil];
    });
});