2010-08-20 3 views
7

Ich habe eine Kerndaten App mit 2 Ansichten. Die erste Ansicht listet "Räume" auf, die zweite Liste "Szenen" in Räumen. Die Rooms-Seite verfügt über eine NavItem-Schaltfläche zum Bearbeiten, die, wenn sie gedrückt wird, eine NavItem-Schaltfläche hinzufügt. Sie können Räume von hier löschen und hinzufügen. Hinzugefügte Räume erscheinen einfach mit einem Standardnamen "Neuer Raum" in der Tabelle. Die zweite Ansicht ist eine Liste von Szenen im ausgewählten Raum. Gleiches gilt hier, Sie können Szenen löschen und hinzufügen, und hinzugefügte Szenen erscheinen einfach in der Tabelle mit dem Namen "Neue Szene". Nichts Besonderes wirklich.Core Data App stürzt ab mit "controllerWillChangeContent: unerkannter Selektor an Instanz gesendet"

Ich verwende eine FetchedResultsController in beiden View-Controller, mit den Szenen eine NSPredicate, nur Szenen aus dem ausgewählten Raum zurückgeben. Ich verwende auch die controllerWillChangeContent, controllerDidChangeContent etc. Delegate-Methoden für die Tabellenansicht Updates.

Dies alles funktioniert zuerst gut, aber in der Regel nach dem Navigieren in Räumen und Szenen und dann versuchen, eine Szene zu löschen, wird es abstürzen. Es wird unweigerlich zum Absturz bringen, wenn Sie lange genug damit spielen. Es passiert nur beim Löschen einer Szene. Wenn Sie die Bearbeitungsschaltfläche drücken und eine Szene löschen und es funktioniert, funktionieren alle folgenden Löschungen in dieser Bearbeitungssitzung immer. Es stürzt nur beim ersten Löschen der Editiersitzung ab.

Der Fehler, den ich bekommen, ist ein seltsamer:

App beenden aufgrund nicht abgefangene Ausnahme 'NSInvalidArgumentException', Grund: '- [__ NSCFType controllerWillChangeContent:]: Unbekannter Selektor gesendet Instanz 0x5e02d70'

Der erste Teil dieses Fehlers ändert sich manchmal. Manchmal ist es __NSCFType, manchmal ist es CALayer. Dieser Fehler tritt nur beim Löschen von Szenen auf. Hinzufügen von Szenen ist in Ordnung 100%.

Ich habe einen anderen Beitrag auf Stackoverflow gelesen, die darauf hindeutet, dass diese Art von Fehlern von Speicherverwaltungsproblemen kommen kann. Ich habe den Code zweimal überprüft und mit dem Leckinstrument durch die Instrumente geleitet. Es gibt keine Lecks.

Kann ich noch etwas überprüfen? Irgendwelche Ideen?

Hier ist der entsprechende Code ..

Von ScenesTableViewController.m:

// used to show/hide the add button 

- (void)setEditing:(BOOL)editing animated:(BOOL)animate 
{ 
    [super setEditing:editing animated:animate]; 
    if(editing) 
    { 
     self.navigationItem.leftBarButtonItem = addButton; 
    } 
    else 
    { 
     self.navigationItem.leftBarButtonItem = nil; 
    } 
} 

// called when the add button is pressed 

- (void)addAction { 
    NSEntityDescription *myContentEntity = [NSEntityDescription entityForName:@"Scene" inManagedObjectContext:managedObjectContext]; 
    Scene *contentToSave = [[Scene alloc] initWithEntity:myContentEntity insertIntoManagedObjectContext:managedObjectContext]; 
    [contentToSave setValue:@"New Scene" forKey:@"Name"]; 
    [parentRoom addRoomToScenesObject:contentToSave]; 

    NSError *error; 
    if (![managedObjectContext save:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     exit(-1); 
    } 
    [contentToSave release]; 
} 

// delegate method that's being sent unrecognised selectors 

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates. 
    [self.tableView beginUpdates]; 
} 

// cell display code 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = nil; 
    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (!cell) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle 
             reuseIdentifier:CellIdentifier] autorelease]; 
     [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; 
    } 
    [self configureCell:cell atIndexPath:indexPath]; 
    return cell; 
} 

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { 
    NSManagedObject *mo = nil; 
    NSString *temp = nil; 
    mo = [fetchedResultsController objectAtIndexPath:indexPath]; 
    temp = [mo valueForKey:@"Name"]; 
    [[cell textLabel] setText:temp]; 
} 

// cell editing code 

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 

    if (editingStyle == UITableViewCellEditingStyleDelete) { 
     // Delete the managed object at the given index path. 
     [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]]; 

     NSError *error; 
     if (![managedObjectContext save:&error]) { 
      // Update to handle the error appropriately. 
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
      exit(-1); // Fail 
     } 
    } 
    else if (editingStyle == UITableViewCellEditingStyleInsert) { 
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 
    }  
} 

// NSFetchedResultsController code 

- (NSFetchedResultsController *)fetchedResultsController { 

    if (fetchedResultsController != nil) { 
     return fetchedResultsController; 
    } 

    /* 
    Set up the fetched results controller. 
    */ 
    // Create the fetch request for the entity. 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    // Edit the entity name as appropriate. 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Scene" inManagedObjectContext:managedObjectContext]; 
    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:YES]; 
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:nameDescriptor, nil]; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SceneToRoom == %@)", parentRoom]; 

    [fetchRequest setSortDescriptors:sortDescriptors]; 
    [fetchRequest setPredicate:predicate]; 
    [fetchRequest setEntity:entity]; 

    // Edit the section name key path and cache name if appropriate. 
    // nil for section name key path means "no sections". 
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 
    aFetchedResultsController.delegate = self; 
    self.fetchedResultsController = aFetchedResultsController; 

    [aFetchedResultsController release]; 
    [fetchRequest release];  
    [nameDescriptor release]; 
    [sortDescriptors release]; 

    return fetchedResultsController; 
} 

Antwort

28

Dieser Fehler wird höchstwahrscheinlich von einem NSFetchedResultsController kommen, die ein frei Delegierten haben. Haben Sie eine UIViewController, die Sie freigegeben haben und die zugehörige NSFetchedResultsController nicht freigegeben?

+0

Danke für die Antwort Marcus. Meine NSFetchedResultsControllers sind synthetisierte Eigenschaften ihrer UITableViewControllers. In der ViewDidUnload-Methode habe ich self.fetchedResultsController = nil, um den Besitz aufzugeben. Muss ich geholtResultsController auch in dealloc freigeben? –

+0

Ja, jede Eigenschaft, die als 'retain' * festgelegt wurde, muss im' -dealloc' freigegeben werden. Tatsächlich würde ich ** sehr ** empfehlen, alle Eigenschaften auf "Null" zu setzen, auch wenn sie in beiden Methoden nur "zuweisen" sind. –

+0

Vielen Dank Marcus, das ist behoben. Und danke für den Tipp zu den behaltenen Eigenschaften und dem -dealloc. Prost! –

1

Sogar ich konfrontiert das gleiche Problem. Aber für iOS 4.2 das Problem ist NSError initialisiert wird, so wird sie als Abfall behandelt und während der Aktualisierung/Einfügen wir haben

if (![managedObjectContext save:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     exit(-1); 
    } 

So speichern die iOS den Fehler als Abfall behandelt und so die Ausnahme. Versuchen Sie, es auf Null zu initialisieren. Es hat mein Problem gelöst. Das Problem tritt nur bei 4.2iOS auf.