0
votes

I am using Justin Driscoll's article on Core Data with UIManagedDocument in singleton pattern to set it up for UITabViewController. I am running the app on Simulator. Its working fine for the first time. The database is created successfully and I can see data in the tableview controller for each tab. But when I restart my application, the tableviews are empty because NSFetchRequest fetches 0 matches for the entity. The same fetch request fetches correct result during the first run.

I think its something to do with asynchronous nature of loading data and data not autosaving before I stop the app in simulator. So data is not available in second run of app.

The way I am doing my data loading as seen in the code. The fetchDataIntoDocument method does the initial loading of data.

// Document Handler Singleton Class

 -(void) performWithDocument:(OnDocumentReady)onDocumentReady {

     void (^OnDocumentDidLoad)(BOOL) = ^(BOOL Success) {
              onDocumentReady(self.document);
     };

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]]) {
        **[self fetchDataIntoDocument:self.document];**  
        [self.document saveToURL:self.document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateClosed) {
        [self.document openWithCompletionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateNormal) {  
        OnDocumentDidLoad(YES);
    }
 }

 -(void)fetchDataIntoDocument:(UIManagedDocument *)document {

       MyEntityDataController *dc= [[MyEntityDataController alloc] init];
       NSDictionary *entityInfo  =[dc getEntityInfo];
       [document.managedObjectContext performBlock:^{
                 [Entity createEntityWithInfo:entityInfo   inManagedObjectContext:document.managedObjectContext];
       }];
 }

My TableViewController class

 -(void)viewWillAppear:(BOOL)animated {

      [super viewWillAppear:animated];
      if (!self.databaseDocument) {
           [[LTDatabaseDocumentHandler sharedDatabaseDocumentHandler] performWithDocument:^    (UIManagedDocument *document) {
           self.databaseDocument = document;
           [self populateTableViewArrayFromDocument:self.databaseDocument];
           }];
      }
  } 

Within populateTableViewArrayFromDocument I am executing my fetch request

  -(void)populateTableViewArrayFromDocument:(UIManagedDocument *)document
{
       NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Entity2"];
       NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
     NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
      [request setSortDescriptors:sortDescriptors];

     NSError *error = nil;
     NSArray *matches = [self.databaseDocument.managedObjectContext  executeFetchRequest:request error:&error];
     NSLog(@" matches count for Entity2 %d", matches.count);
     for (Entity2 *entity2 in matches) {
        //do stuff with data and add it to tableview array
     }
    }
1

1 Answers

1
votes

I think I have found why you have this problem. I have just run into this issue and it took some research to figure it out. Basically, you are right. The problem is indeed in the asynchronous nature of UIManagedDocument. You need to wait until the document loads into memory and then do your fetching.

This is the code I use to make sure the document is ready:

 if ([[NSFileManager defaultManager] fileExistsAtPath:[_URLDocument path]]) {
        [_managedDocument openWithCompletionHandler:^(BOOL success){
            [self ready]
            if (!success) {
                // Handle the error.
            }
        }];
 } 

Hope this helps, cheers!