Reputation: 798
I have an NSMutableArray in a "sharedStore"-pattern singleton.
Publicly, it's accessible only through methods that cast it as an NSArray. Within the class, it's
@property (nonatomic, copy) NSMutableArray *myItems;
This array never gets manipulated outsdie the singleton but ViewControllers send the singleton messages to manipulate this controller. Some of these messages empty the array, some re-populate it, etc.
Having ended up in a situation where the array was empty in one method call and not yet empty in the next, I've started implementing some concurrency behaviour.
Here's what I'm doing so far:
In the .m file of the singleton, I have a
@property (nonatomic, strong) dispatch_queue_t arrayAccessQueue;
In my singleton's initializer it gets created as a serial queue. And then, every method that has anything to do with mutating this array does so from within a dispatch_sync
call, for example:
dispatch_sync(self.arrayAccessQueue, ^{
[_myItems removeAllObjects];
});
This has made things better and has made my app behave more smoothly. However, I have no way of quantifying that beyond it having fixed that one odd behaviour described above. I also kind of feel like I'm in the dark as to any problems that may be lurking beneath the surface.
This pattern makes sense to me, but should I be using something else, like @synchronize
or NSLock
or NSOperationQueue
? Will this come back to bite me?
Upvotes: 4
Views: 787
Reputation: 26385
Using a GCD queue concurrent and providing sort of accessor to your array you can synchronize reading and writing by using dispatch_sync while reading and dispatch_barrier_async while writing.
- (id)methodToRead {
id __block obj = nil;
dispatch_sync(syncQueue, ^{
obj = <#read_Something#>;
});
return obj;
}
- (void) methodsForWriting:(id)obj {
dispatch_barrier_async(syncQueue, ^{
// write passing obj to something
});
}
This will guarantee that during writing everything is locked from reading.
Upvotes: 1
Reputation: 318824
Using dispatch_sync
is fine as long as you wrap all array reads and writes and you ensure it is a serial queue.
But you could improve things by allowing concurrent reads. To do this, use dispatch_sync
around all array reads and use dispatch_barrier_sync
around all array writes. And setup the queue to be concurrent.
Do this ensures only a single write can happen at a time, reads will be block until the write is done, and a write will wait until all current reads are done.
Upvotes: 4
Reputation: 5300
Using GCD is the right choice. The only "gotcha" is that you need to do ALL operations on that queue: add, remove, insert, etc.
I will also mention you need to ensure that you do not use a concurrent queue. You should be using a serial queue, which is the default anyways.
Upvotes: 0