1

伙计们!我正在我的应用程序中实现共享缓存。这个想法是在后台从 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. 这真的会像我认为的那样做吗?如果是这样,这是迄今为止处理这种情况的最干净的方法吗?有一篇博客文章与我所说的非常接近,但我也想与您再次确认。
  2. 我在想,只要我只在同一个线程/队列(在我的情况下是 main)上访问共享共享资源并且只在 main 上更新 UI,那么我将有效地实现线程安全。那是对的吗?

谢谢!

4

2 回答 2

1

如果你问 100 位开发人员,这是最优雅的方法,你会得到至少 100 个不同的答案(也许更多!)

我所做的,对我来说效果很好的,是让一个单身班级来做我的图像管理。我使用 Core Data,并将缩略图直接保存在商店中,但在 Core Data 中使用文件系统和指向它的 URL 来获取“大”文件。Core Data 设置为使用新的基于块的接口,因此它可以在自己管理的私有线程上完成所有工作。

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

当图像最终添加到存储库中时,moc 会在主队列上调度一个带有接收到的图像标签的通知。想要图像的类可以监听这个,当他们得到它时(在主线程上)他们可以再次向 moc 请求图像,这显然是存在的。

于 2012-09-28T13:44:43.580 回答
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];
    });
});
于 2012-09-28T14:15:03.167 回答