I have some model classes that I need to synchronize. There is a main object of type Library
that contains several Album
objects (imagine a music library, for example). Both the library and albums support serialization by implementing the NSCoding
protocol. I need to synchronize modifications to the library with album modifications and the serialization of both classes, so that I know the updates don’t step on each other’s toes and that I don’t serialize objects in the middle of an update.
I thought I would just pass all the objects a shared dispatch queue, dispatch_async
all the setter code and dispatch_sync
the getters. This is simple and easy, but it does not work, as the program flow is recursive:
// In the Library class
- (void) encodeWithCoder: (NSCoder*) encoder
{
dispatch_sync(queue, ^{
[encoder encodeObject:albums forKey:…];
});
}
// In the Album class, same queue as above
- (void) encodeWithCoder: (NSCoder*) encoder
{
dispatch_sync(queue, ^{
[encoder encodeObject:items forKey:…];
});
}
Now serializing the library triggers the album serialization and since both method use dispatch_sync
on the same queue, the code deadlocks. I have seen this pattern somewhere:
- (void) runOnSynchronizationQueue: (dispatch_block_t) block
{
if (dispatch_get_current_queue() == queue) {
block();
} else {
dispatch_sync(queue, block);
}
}
Does it make sense, will it work, is it safe? Is there an easier way to do the synchronization?