共享资源访问 + UI 更新的 GCD 模式?
Posted
技术标签:
【中文标题】共享资源访问 + UI 更新的 GCD 模式?【英文标题】:GCD pattern for shared resource access + UI update? 【发布时间】:2012-09-28 08:11:58 【问题描述】:伙计们!我正在我的应用程序中实现共享缓存。这个想法是在后台从 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];
);
);
-
这真的会像我认为的那样做吗?如果是这样,这是迄今为止处理这种情况的最干净的方法吗?有一个 blog post 与我所说的非常接近,但我也想与您再次确认。
我在想,只要我只在同一个线程/队列(在我的情况下为 main)访问共享共享资源并且只在 main 上更新 UI,那么我将有效地实现线程安全。对吗?
谢谢!
【问题讨论】:
【参考方案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];
);
);
【讨论】:
太好了,感谢大家确认我确实走在了正确的轨道上。让缓存类在内部使用它自己的自定义队列听起来确实是一个很好的方法,并且允许我保证线程安全,而被调用者不需要了解任何内部信息! 为什么 dispatch_sync(dispatch_get_main_queue() 而不是 dispatch_async? @user523234 我以为没关系。 经过反思,如果通知接收者尝试执行读取,可能会导致死锁。【参考方案2】:如果你问 100 位开发人员,这是最优雅的方法,你会得到至少 100 个不同的答案(也许更多!)
我所做的,并且对我来说效果很好的,是让一个单例类来做我的图像管理。我使用 Core Data,并将缩略图直接保存在商店中,但在 Core Data 中使用文件系统和指向它的 URL 来获取“大”文件。 Core Data 设置为使用新的基于块的接口,因此它可以在自己管理的私有线程上完成所有工作。
可能的图像 URL 被注册到主线程上的标记中。其他类可以请求该标签的图像。如果图像不存在,则返回 nil,但该类设置一个 fetchingFlag,使用与 NSURLConnection 耦合的并发 NSOperation 来获取图像,当它获取到它时,它会在其线程上使用接收到的图像数据向单例发送消息,并且获取该消息的方法使用 '[moc performBlock:...]'(无需等待)来处理它。
当最终将图像添加到存储库中时,moc 会在主队列上调度带有接收到的图像标签的通知。需要图像的类可以监听这个,当他们得到它时(在主线程上)他们可以再次向 moc 请求图像,这显然是存在的。
【讨论】:
太棒了,感谢您解释如何处理这种情况,大卫!以上是关于共享资源访问 + UI 更新的 GCD 模式?的主要内容,如果未能解决你的问题,请参考以下文章