I'm playing around with UIDocument recently and confuse with concept on dispatch_sync/dispath_async
I have a method that fetch all documents information
for (int i=0; i < noteDocuments.count; i++) {
NSURL * fileURL = [noteDocuments objectAtIndex:i];
NoteDocument *doc = [[NoteDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
[doc closeWithCompletionHandler:^(BOOL success) {
[self addOrUpdateInfoWithDoc:doc];
}];
}];
}
Everything work fine with this simple approach.
Then I try to dispatch_sync/dispath_async
First with dispath_sync
dispatch_sync(dispatch_queue_create("test", DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
for (int i=0; i < noteDocuments.count; i++) {
NSURL * fileURL = [noteDocuments objectAtIndex:i];
NoteDocument *doc = [[NoteDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
[doc closeWithCompletionHandler:^(BOOL success) {
[self addOrUpdateInfoWithDoc:doc];
}];
}];
}
});
After add dispatch_sync like this, method never finish. This confusing me because dispath_sync should return to main queue after block was executed which in this case an openWithCompletionHandler
should return immediately.
Then with curiosity I change it to dispatch_async (just for experiment)
dispatch_async(dispatch_queue_create("test", DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
for (int i=0; i < noteDocuments.count; i++) {
NSURL * fileURL = [noteDocuments objectAtIndex:i];
NoteDocument *doc = [[NoteDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
[doc closeWithCompletionHandler:^(BOOL success) {
[self addOrUpdateInfoWithDoc:doc];
}];
}];
}
});
The result also confusing me, I got EXC_BAD_INSTRUCTION on line [doc openWithCompletionHandler:^(BOOL success) {
Can anyone explain what going under the hood ? This is what I understand, but it obviously wrong.
I believe NoteDocument class is derived from UIDocument class.
So -openWithCompletionHandler: completionHandler is invoked on the main queue.Also I believe the following your code on the main queue (the main thread).
It means you intended to wait to finish the queue in the main queue. Yes, it blocks the main queue until the queue was finished.
openWithCompletionHandler: finished to open the document, and then it submitted the completionHandler block to the main queue, but the main queue had been blocked by dispatch_sync. So the completionHandler block will never be invoked. Thus, the "test" queue will never finish and dispatch_sync also will never finish.
And EXC_BAD_INSTRUCTION, I doubt -openWithCompletionHandler: could be called from the other thread. I'm not sure but you might need to call the method from the main thread.
By the way, you might misunderstand the 2nd argument of dispatch_queue_create.
The 2nd argument is attr, it's not for the priority of the queue.
Luckily, it's not problem in this case. In '''/usr/include/dispatch/queue.h'''
is the same as
EDIT
If UIDocument -openWithCompletionHandler: is ordinary method, it wouldn't cause DEADLOCK. It would be the following sequence.
But, according to LLDB stack trace, it seems a bit different from the other method.
So the sequence would be the following.
Thus, DEADLOCK.