我希望能为我的应用提供一些帮助。
我有一个设置,其中多个线程访问由singleton类拥有的共享NSMutableDictionary
。线程访问字典以响应下载JSON并对其进行处理。单例类基本上防止了一些具有唯一ID号的下载对象的重复。
即。
//NSURLConnection calls:
[[Singleton sharedInstance] processJSON:data];
@interface Singleton
+ (Singleton) sharedInstance;
@property (nonatomic, strong) NSMutableDictionary *store;
@end
@implementation
-(void) processJSON:(NSData*)data {
...
someCustomClass *potentialEntry = [someCustomClass parse:data];
...
if(![self entryExists:potentialEntry.stringId])
[self addNewEntry:potentialEntry];
...
}
-(void) entryExists:(NSString*)objectId {
if(self.store[objectId])
return true;
else return false;
}
-(void) addEntry:(someCustomClass *object) {
self.store[object.stringId] = object;
}
一次调用processJSON可以有多达5-10个线程。
不是马上但运行几分钟后(在iPhone上比在模拟器上更快)我得到了可怕的EXC BAD ACCESS。
我不承认知道NSMutableDictionary
是如何工作的,但我猜测后台中有某种哈希表需要在分配对象时更新并在访问对象时读取。因此,如果线程即时读取/写入字典,可能会发生此错误 - 可能是因为对象已在内存中移动?
我希望有更多关于这个主题的知识可以启发我!
至于解决方案,我考虑的是单例类,NSOperationQueue
的最大并发操作数为1,然后在我想访问operationWithBlock:
时使用NSDictionary
。唯一的问题是它使调用processJSON
成为一个异步函数,我无法立即返回创建的对象;我必须使用一个块,这将有点麻烦。有没有办法使用@synchronize
?那会有用吗?
答案 0 :(得分:2)
我会提请你注意Hot Licks指出的线程编程指南的iOS版本的Synchronization部分。其中一个锁定机制或使用专用串行队列可以帮助您实现线程安全。
你对串行操作队列的直觉是有希望的,尽管人们常常会为此使用串行调度队列(例如,你可以从任何队列调用dispatch_sync
到你的字典的串行队列),实现两者的控制与它交互的机制以及同步操作。或者,更好的是,您可以使用自定义并发队列(不是全局队列),并通过dispatch_sync
执行读取并通过dispatch_barrier_async
执行写入,从而实现高效的读取器/写入器方案(如{ {3}}或WWDC 2011 - Mastering GCD)。
并发编程指南的WWDC 2012 - Asynchronous Design Patterns部分概述了使用串行队列进行同步与传统锁定技术的一些基本原理。
并发编程指南中的Eliminating Lock-Based Code和Grand Central Dispatch (GCD) Reference应提供相当多的信息。
答案 1 :(得分:0)
最简单的解决方案就是将所有访问dict的代码放在@synchronized块中。
串行操作队列很棒,但听起来对我来说太过分了,因为你没有守护整个数据生态系统,只有一个结构......