Question

I've been reading everything I can here about UIDocument and UIManagedDocument since there is more help on UIManagedDocument and it's a subclass of UIDocument, but I've not been able to figure what I need to do about this.

When the user hits the add button for my app to create a new document I need to create the document and have a couple of items prepopulated into it. My code for doing this works fine as long as I am single-stepping through the debugger, but at full speed the couple of items don't make it into the document.

I store a reference to the document in my AppDelegate and have a macro defined for simplified reading in the code:

#define SelectedDocument [(AppDelegate *)[[UIApplication sharedApplication] delegate] selectedDocument]

So in handling the add request, my code does this:

GnKDocument *tmp = [[GnKDocument alloc] initWithFileURL:fileURL];
[(AppDelegate *)[[UIApplication sharedApplication] delegate] setSelectedDocument:tmp];
[SelectedDocument saveToURL:fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
    if (success) {
        [SelectedDocument openWithCompletionHandler:^(BOOL success) {
            if (success) {
                [SelectedDocument setDateCreated:[NSDate date]];
                NSString *c1UUID = [SelectedDocument appendChapterWithName:@"Chapter 1"
                                                               withColor:kChapterColorYellow];
                NSString *p1c1UUID = [SelectedDocument appendPageWithParent:c1UUID
                                                                       withName:@"Page 1"
                                                                      withColor:kPageColorRed];
                NSLog(@"Just added Page 1 as %@ to chapter %@", p1c1UUID, c1UUID);
                [SelectedDocument closeWithCompletionHandler:^(BOOL success) {
                 }];
            }
     }
 }];

The two append calls into my UIDocument subclass do their work and then call

[self updateChangeCount:UIDocumentChangeDone];

And as a testing step I overrode that method just to log out that changes were being made:

- (void)updateChangeCount:(UIDocumentChangeKind)change
{
     [super updateChangeCount:change];
     NSLog(@"GnKDocument recording a change");
}

Am I doing things in the right order? Should I be dispatching calls off to various queues?

  1. Init the instance
  2. Save it for creating
  3. Open it (to add my initial items to it)
  4. Make my additions
  5. Close it (according to the docs, closeWithCompletionHandler: asynchronously saves any changes).

Again, if I set breakpoints at each call (saveToURL:, openWithCompletionHandler:, and closeWithCompletionHandler) and "step over" those calls, then run to get into the completion handlers, the document ends up on disk as I intended. If I disable my breakpoints and run again, the document is created on disk and the changes are logged, but the closed file does not contain my two initial elements.

Was it helpful?

Solution

For the longest time I thought the difference was the speed with which the code was executing was either creating or avoiding a race condition. But in investigating that possibility I added lots of NSLog statements everywhere something critical was happening... and the problem went away. So it clearly wasn't a timing issue. Looking back over the contents of the NSLog statements I realized that some of the values were being lazy-loaded, and the act of referencing them in the NSLog statements was causing them to be loaded. Similarly, while single-stepping through the code, I suspect that "Print description of..." commands were having the same effect (maybe).

So in my case, the UIDocument subclass builds a file wrapper that contains two files, one for metadata about the document and another that is the actual document data. There was a test to verify minimal correctness in the document, and this test used values from the metadata file which were meant to be lazy loaded but had never been accessed, so the test determined the file was not valid and set up the initial values all over again, wiping out the two items I was prepopulating the file with.

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