Warum NSFetchedResultsController ist nicht mit neuen Daten aktualisiert?
Mein Core Data-Modell verfügt über zwei Einheiten: Author
und Book
mit einem Zu-Viele-Beziehung (one-author->viele Bücher). In der Hauptansicht ich die Anzeige einer Liste von Büchern, in denen jede Zelle enthält buchname und name des Autors. Die Ansicht ist ebenfalls in Abschnitte unterteilt, wobei jeder Abschnitt Titel ist der name des Autors. (beachten Sie, dass "Autor.name" festgelegt ist, für beide sort-descriptor und sectionNameKeyPath)
Hier ist der code (aus Gründen der übersichtlichkeit vereinfacht):
- (NSFetchedResultsController *)fetchedResultsController {
if (__fetchedResultsController != nil) {
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"author.name" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"author.name" cacheName:nil] autorelease];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
return __fetchedResultsController;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
Book* book = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", book.name, book.author.name];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller {
[self.tableView reloadData];
}
Nun, wenn der Benutzer ändert den Namen des Autors und geht dann zurück zur Hauptansicht, die Zellen und die Abschnitte zeigen die alten den Namen des Autors. Nach der Suche im Internet fand ich den folgenden code, welche Updates den alten Namen des Autors-Ausgabe in den Zellen, aber nicht im Abschnitt Titel:
- (void)saveAuthorName:(NSString *)newName {
for (Book* book in author.books) {
[book willChangeValueForKey:@"author"];
}
author.name = newName;
for (Book* book in author.books) {
[book didChangeValueForKey:@"author"];
}
//save changes
NSError * error ;
if( ![self.moc save:&error] ) {
//Handle error
}
}
Warum ist [self.fetchedResultsController sections]
enthält noch den alten Namen der Autoren? Bitte um Hilfe!!
Update #1
Dieser Abschnitt bezieht sich auf Antwort #1 von Marcus
Hmmm, immer noch ein wenig verschwommen. Sagen Sie die Anzahl der Abschnitte ist falsch?
Die Anzahl der Abschnitte wurde nicht geändert. Der Inhalt der Objekte in der Sections
Eigenschaft array ist falsch.
Basierend auf Ihren code gepostet Sie einfach abrufen die NSManagedObject-Instanzen aus dem NSFetchedResultsController. Vielleicht gibt es einige Verwirrung, was das ist?
In den code, ich bin das abrufen der NSManagedObject
Instanzen aus der NSFetchedResultsController
um das anzeigen der buchname und name des Autors für jede Zelle in der Tabelle (wenn cellForRowAtIndexPath
genannt wird). Allerdings werden die überschriften der einzelnen Abschnitte in UITableView
nicht aus NSManagedObject
nach meinem Verständnis aber sind genommen aus _NSDefaultSectionInfo
Objekt implementiert die NSFetchedResultsSectionInfo
Protokoll (wenn titleForHeaderInSection
genannt wird).
Erkannte ich, dass dies durch den folgenden code, den ich schrieb für debugging:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
id mySection = [[fetchedBooks sections] objectAtIndex:section];
NSLog(@"%@", mySection)
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
Das Ergebnis des log <_NSDefaultSectionInfo: 0x8462b90>.
NSFetchedResultsController Dokumentation für die Abschnitte Eigenschaft zeigt:
/* Returns an array of objects that implement the NSFetchedResultsSectionInfo protocol.
It's expected that developers use the returned array when implementing the following methods of the UITableViewDataSource protocol
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
*/
Also bitte korrigieren Sie mich, wenn ich falsch bin: _NSDefaultSectionInfo
ist nicht ein NSManagedObject
Recht? Wenn ja, wie kann NSFetchedResultsController
Veränderungen erkennen, die für _NSDefaultSectionInfo
Objekte beim Autor NSManagedObject
geändert werden?
So führt dies zu einer Reihe von Fragen:
Wie ändern Sie den Namen des Autors in dieser anderen Ansicht?
Den code für das ändern der name des Autors bereits oben geschrieben in saveAuthorName
. Die Strömung in der App ist wie folgt:
-
Vom main
UITableView
, die Auswahl der Buch-Zelle, die öffnet neue Buch-Ansicht mit navigation-controller. -
Aus der Buch-Ansicht, wählen Autor wählen, die öffnet neue Select-Author-Ansicht mit navigation-controller. (alle Autoren sind sich in einem denkmalgeschützten
UITableView
) -
Vom Select-Author-Ansicht auswählen aller Autoren, die öffnet neue Bearbeiten-Autor-Ansicht mit navigation-controller.
-
In der Bearbeiten-Autor anzeigen, ändern den Namen des Autors und speichern schließt anzeigen, und bringen Sie die bisherige Ansicht (Wählen-Autor) in Navigations-controller-stack.
-
Es ist nun möglich, wählen Sie verschiedene Autor und Bearbeiten es und so weiter.. bis zum schließen dieser Ansicht. (Bringt Buch-Ansicht)
-
Schließen Buch-Ansicht, bringt für die Haupt-Sicht, in der alle Bücher angezeigt werden.
Ist der name des Autors in der Zelle alt oder nur die Kopfzeile des Abschnitts?
Zelle ist vollkommen aktualisiert mit dem Namen des Autors (vielen Dank an die willChangeValueForKey
und didChangeValueForKey
genannt in saveAuthorName
). Nur Abschnitts-header ist alt.
Was machen deine delegieren Methoden Aussehen?
könnten Sie bitte angeben, welche genau? Ich schrieb alle Delegierten Methoden, die sieht für mich relevant im obigen code-Abschnitt. Dies beinhaltet:
-
cellForRowAtIndexPath
-
titleForHeaderInSection
-
controllerDidChangeContent
Andere Methode erforderlich?
Sind Sie sicher, dass Ihr -[UITableViewDatasource tableView: titleForHeaderInSection:] ist das feuern, nachdem Sie wieder aus dem edit?
100% Prozent sicher. titleForHeaderInSection
bringt die alten Werte, und es wird aufgerufen, nachdem die änderungen gespeichert wurden. (cellForRowAtIndexPath
ist auch aufgerufen, nachdem die änderungen gespeichert wurden, aber bringt neue Werte)
Was NSFetchedResultsControllerDelegate Methoden sind brennen nach der Rückkehr?
Wenn du meinst, beim speichern (d.h. nach saveAuthorName
aufgerufen wird) folgenden Methoden aufgerufen wird:
-
controllerWillChangeContent:
(nicht benutzen, nur für debug-info) -
controller:didChangeObject:
(nicht benutzen, nur für debug-info) -
controllerDidChangeContent:
Wenn du meinst, nach der Rückkehr zur Hauptansicht (bedeutet, dass das schließen der Buch-Ansicht) folgenden Methoden aufgerufen wird:
-
cellForRowAtIndexPath
-
titleForHeaderInSection
-
numberOfSectionsInTableView
-
numberOfRowsInSection
Ich Schätze Ihre Hilfe. Danke!
Update #2
Sind Sie der Umsetzung -controller: didChangeSection: atIndex: forChangeType:?
Ja, das Tue ich aber nicht gefeuert zu werden, wenn Sie ändern Sie den Namen des Autors. Die aktuelle Konfiguration für die NSFetchedResultsController
ist wie folgt:
- Einheit: Buch
- Sort-Descriptor: der Autor.name
- sectionNameKeyPath: Autor.name
Ändern ein Buch Namen (anstatt den Namen des Autors) wird Feuer didChangeSection
Ereignis, wenn NSFetchedResultsController
ist wie folgt konfiguriert:
- Einheit: Buch
- Sort-Descriptor: der name
- sectionNameKeyPath: name
Was bedeutet, dass die Stellvertretung ist richtig süchtig nach den NSFetchedResultsController.
Sieht es als Berufung [book willChangeValueForKey:@"author"]
und [book didChangeValueForKey:@"author"]
beim ändern der name des Autors ist nicht genug für NSFetchedResultsController
um die monitor-Sektion ändert.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Generell sollten Sie nicht brauchen, um die änderungen zu speichern, wenn Sie sind den Umgang mit einer einzigen
NSManagedObjectContext
sowohl für dieNSFetchedResultsController
und dieUIViewController
ist, dass die änderungen vornehmen.Dies gilt nicht, wenn Sie mehr als eine
NSManagedObjectContext
.Vorausgesetzt, Sie haben ein
NSManagedObjectContext
ich würde stellen Sie sicher, dass die Delegierten setzen auf dieNSFetchedResultsController
und setzen Sie break-points in der delegate-Methoden zu sehen, wenn Sie immer alle Rückrufe an alle.Ich würde auch den debugger verwenden, und drucken Sie die Zeiger für die NSManagedObject(s) mit dem Sie arbeiten und stellen Sie sicher, Sie sind die gleichen. Wenn Sie nicht sind, dann würde es zeigen, um ein Problem mit der
NSManagedObjectContext
.Antwort #1
Hmmm, immer noch ein wenig verschwommen. Werden Sie sagen, die Anzahl der Abschnitte ist falsch?
Basierend auf Ihren code gepostet Sie einfach abrufen die
NSManagedObject
Instanzen aus derNSFetchedResultsController
. Vielleicht gibt es einige Verwirrung, was das ist?Den
NSFetchedResultsController
ist lediglich ein container, der eine oder mehrere Abschnitte. Diese Abschnitte werden auch nur ein container, enthält eine oder mehrere NSManagedObject Instanzen. Das sind die gleichen InstanzenNSManagedObject
Sie würden irgendwo anders in Ihrer Anwendung (unter der Annahme einer einzigenNSManagedObjectContext
design).Deshalb, wenn Sie ändern die Daten in einem
NSManagedObject
überall in Ihrer Anwendung wird aktualisiert werden, in derNSFetchedResultsController
da es das gleiche Objekt ist, und nicht eine Kopie, sondern die exakt gleichen Objekt.So führt dies zu einer Reihe von Fragen:
-[UITableViewDatasource tableView: titleForHeaderInSection:]
ist feuern, nachdem Sie wieder aus dem edit?NSFetchedResultsControllerDelegate
Methoden sind brennen nach der Rückkehr?Antwort #2
Sind Sie der Umsetzung
-controller: didChangeSection: atIndex: forChangeType:
? Wenn nicht, so tun Sie dies bitte und sagen Sie mir, wenn es feuert. Wenn es nicht Feuer, wenn es brennt? Vor oder nach dem Aufruf-[UITableViewDatasource tableView: titleForHeaderInSection:]
?Antwort #3
Dies ist beginnend zu klingen wie ein Apple bug.
Ein paar Gedanken:
Heute mit Swift alles, was einfacher ist.
NSFetchedResultsControllerDelegate
im controllerNSFetchedResultsController
.performFetch
auf IhrefetchedResultsController
es schluckt die Veranstaltung, die normalerweise geht an die Delegierten.Warum nicht Sie verpflichten sich, die Transaktionen speichern der änderungen?