How to populate the master data repository programmatically?

Edit: A minimal project that shows a failure can be downloaded from crashTest . It was created by selecting the project template "Navigation Based on Master Data" in Xcode and changing perhaps ten lines.

I ran into hair to break out with a crash when a section and two objects were added at a time.

A failure occurs at the end of the procedure inside the call [managedObjectContext save:&error].

Failure is an exception from abroad for NSArray:

Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFArray objectAtIndex:]: index (1) beyond bounds (1) with userInfo (null)

It is also possibly relevant when an exception occurs, my procedure for selecting the resulting controller controllerDidChangeContent:is in the call stack. It just calls my view table endUpdate.

Now I'm running out of ideas. How can I insert more than one element into a kernel data warehouse with a table view using partitions?

Here is the call stack:

#0  0x901ca4e6 in objc_exception_throw
#1  0x01d86c3b in +[NSException raise:format:arguments:]
#2  0x01d86b9a in +[NSException raise:format:]
#3  0x00072cb9 in _NSArrayRaiseBoundException
#4  0x00010217 in -[NSCFArray objectAtIndex:]
#5  0x002eaaa7 in -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:]
#6  0x002def02 in -[UITableView endUpdates]
#7  0x00004863 in -[AirportViewController controllerDidChangeContent:] at AirportViewController.m:463
#8  0x01c43be1 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:]
#9  0x0001462a in _nsnote_callback
#10 0x01d31005 in _CFXNotificationPostNotification
#11 0x00011ee0 in -[NSNotificationCenter postNotificationName:object:userInfo:]
#12 0x01ba417d in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:]
#13 0x01c03763 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:]
#14 0x01b885ea in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:]
#15 0x01bbe728 in -[NSManagedObjectContext save:]
#16 0x000039ea in -[AirportViewController populateAirports] at AirportViewController.m:112

Here is the code for the routine. I apologize because a series of lines probably doesn't matter, but I'd rather be mistaken on this side. A failure occurs when it causes [context save:&error]:

- (void) insertObjects
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];

NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

// If appropriate, configure the new managed object.
[newManagedObject setValue:@"new airport1" forKey:@"name"];
[newManagedObject setValue:@"???" forKey:@"code"];
[newManagedObject setValue:@"new country" forKey:@"country_name"];

newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
[newManagedObject setValue:@"new airport2" forKey:@"name"];
[newManagedObject setValue:@"???" forKey:@"code"];
[newManagedObject setValue:@"new country" forKey:@"country_name"];


// Save the context.
NSError *error = nil;
if (![context save:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}
}

Note: sections are indicated by country_name. In addition, the four routines NSFetchedResultsControllerDelegateare as documented as the ones given by Xcode:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
       atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
    case NSFetchedResultsChangeInsert:
        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;
// other cases omitted because not occurring in this crash            

}
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;

switch(type) {

    case NSFetchedResultsChangeInsert:
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
// other cases omitted because not occurring in this crash            
}
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
+5
source share
3 answers

It seems to me that this is a bug in Cocoa Touch. Maybe I'm wrong. Anyway, I found a job around.

, , . , iVar BOOL massUpdate, true, , reset - false .

massUpdate iVar. , , , .

:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
if (massUpdate)
    return;
[self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
       atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
if (massUpdate)
    return;
    <snip normal implementation>
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
if (massUpdate)
    return;
    <snip normal implementation>
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
if (massUpdate)
    [self.tableView reloadData];
else
    [self.tableView endUpdates];
}
+3

UITableView ( ). insertRowsAtIndexPaths:withRowAnimation: beginUpdates/endUpdates. "" , numberOfRowsInSection , .

beginUpdates controllerWillChangeContent:? , NSFetchedResultsControllerDelegate docs " ?". , controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:, ? , , .

+1

Cocoa Touch. , .

objc_exception_throw, . , , , .

, , - . , -numberOfSectionsInTableView:, -tableView:numberOfRowsInSection:. .

UPDATE

, . , Core Data Cocoa Touch. , , , .

Event NSFetchedResultsController . , .

:

  • Event . / , , . Event , NSFetchedResultsController, -, .
  • Create Event objects before initializing NSFetchedResultsController. This is the initial update of the section name cache that causes the error, so if objects exist before the cache, it will not throw.

I must admit that this is one of the most interesting disasters that I have seen, and I will send a radar to it. I suggest you do the same so that it can be fixed in (hopefully) the next version of the OS.

+1
source

All Articles