Question

I'm having trouble getting my head around the way UIDocuments open asynchronously. I have a series of UIDocuments that the user has created. When the user presses a button I need to open some of the documents, pull some strings from them, and concatenate the strings into a new file.

I have an array that keeps track of which documents need to be opened. My thought was that I should loop through the array, open each document, and append its contents to an NSMutableString. The problem is that openWithCompletionHandler does its work asynchronously, so the loop marches ahead and finishes, returning an empty string, before the documents have been opened (and closed again).

Here's a little bit of code:

__block NSMutableString *combinedString;

for (entryClass *entry in documentList)
{
    MyDocumentClass *document = [[MyDocumentClass alloc] initWithFileURL:[entry fileURL]];

    if ([document documentState] & UIDocumentStateClosed) {
        [document openWithCompletionHandler:^(BOOL success) {

            if (success) {
                [combinedString appendString:[document documentBody]];
            }

            [document closeWithCompletionHandler:nil];
        }];
    }
}

NSLog(@"Combined String: %@", combinedString);

Naturally what happens is that combinedString comes back empty because the loop finishes while the documents are opening in the background. I could move the document handling to its own method that returns a string but I think this will still return before the document is read. I'll presumably have to put up a progress indicator and make user wait--that's probably okay.

Was it helpful?

Solution

You can do this with dispatch groups. See the sections "Groups" and "Using dispatch_group_t with Existing API" at Low-Level Concurrency APIs.

OTHER TIPS

I've had to do something very similar and rather than delving into low level functions I opened the document with openDocumentWithContentsOfURL:display:completionHandler:. Because it passes the opened document to the completionHandler you can do the work to extract the data from the document and then close it in the completionHandler block.

This assumes that you don't care what order the documents will write their data to the string, because in theory the completionHandlers for the different document could be run in any order.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top