2014-12-06 6 views
6

Ich führe mein Programm, das Kerndaten Inhalt erstellt, die in mit NSTreeController angezeigt wird. Das zweite Mal, wenn ich mein Programm starte, möchte ich den Inhalt meines NSTreeController säubern und ich führe die unten eingefügte Methode aus. Die Methode hängt lange (600 Sekunden), bevor sie beendet wird oder abstürzt. Wenn ich wenige Entitäten (500-1000) in meinem NStreeController habe, dauert es viel weniger Zeit im Vergleich zu wenn ich viele (200.000) Entitäten habe, um diese Methode zu bestehen, wenn sie überhaupt besteht. Was ich wissen muss, ist, wenn es einen besseren Weg gibt, den Inhalt meines NStreeController zu löschen/zu löschen, um meine NSoutlineView zu löschen, bevor ich mein Programm erneut ausführe und die NStreeController wieder auffülle. Insbesondere möchte ich meine NSOutlineView schnell auf Änderungen an den Inhalten meiner NSTreeController reagieren, und ich muss den Inhalt meiner Core Data NSTreeController, um zurückgesetzt werden können.Reset Core Data driven treeController Inhalt

-(void) cleanSDRDFileObjects 
{ 
    __weak __typeof__(self) weakSelf = self; 
    dispatch_async(dispatch_get_main_queue(), ^{  
     [weakSelf.outlineView collapseItem:nil collapseChildren:YES]; 
     [weakSelf.coreDataController._coreDataHelper.context performBlockAndWait:^{ 

      NSEntityDescription *entityDescription = [NSEntityDescription 
                entityForName:@"SDRDFileObject"          inManagedObjectContext:weakSelf.coreDataController._coreDataHelper.context]; 

      NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
      [request setEntity:entityDescription]; 

      NSArray * result = [weakSelf.coreDataController._coreDataHelper.context executeFetchRequest:request error:nil]; 
      for (id fileobject in result){ 
       [weakSelf.coreDataController._coreDataHelper.context deleteObject:fileobject]; 
      } 
      [weakSelf.coreDataController._coreDataHelper.context processPendingChanges]; 

      NSLog(@"Finished deleting all objects"); 
     }]; 
    }); 
} 

Die managedobjectcontext (context) als Typ ausgeführt wird und das Verfahren NSMainQueueConcurrencyType auf dem Haupt-Thread ausgeführt wird. Vorschläge für Verbesserungen oder nützliche Beispiele für die Kombination von Zurücksetzen/Auffrischen von NSOutlineView + Core-Daten wären sehr willkommen. Vielen Dank. Prost, Trond

Als Antwort auf @ TomHarringtons Frage nahm ich ein Bild von meinem Time Profiler. Ich wirklich nicht t understand why it hangs on this method, however, after commenting this methods out (```processPendingChanges```), it still hangs and takes forever to finish (6 minutes). It seems the process gets stuck on the main thread and can t weiter.

enter image description here

Wenn ich die Anwendung erneut ausführen, mit processPendingChanges seine hängen noch kommentiert werden.

enter image description here

aktualisieren

Ich glaube, ich dieses Problem gelöst, aber ich bin etwas unsicher, warum dies funktioniert. Es scheint, dass meine erste Methode in eine unbestimmte Schleife ging, die ihre Objekte nicht freigab. Die folgende einfache Lösung gearbeitet:

 __weak __typeof__(self) weakSelf = self; 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
     [weakSelf.coreDataController._coreDataHelper.context reset]; 
     }); 

Ich war sicher, dass man richtig ein verwaltetes Objekt Kontext leeren würde ich jede Einheit einzeln löschen. Die Reset-Funktion scheint ziemlich brutal und reinigt tatsächlich den Speicher und stellt sicher, dass alles in Ordnung ist? Wenn jemand etwas Licht darauf werfen möchte, würde das geschätzt werden.

+0

wird/didChangeValueForKey in der Regel von Zugriffsmethoden der 'self' Instanz aufgerufen. Warum würdest du sie von dieser Methode aus anrufen? Und NSTreeController hat nicht einmal einen keyPath "Kinder". Es hat einen keyPath "childrenKeyPath". Unabhängig davon - suchst du nach "rearageObjects" ?? – stevesliva

+0

['rearrangleObjects'] (http://stackoverflow.com/questions/23773827/how-can-i-determinine-if-apple-methods-are-asynchronous/) wird manchmal die Aktualisierung der GUI in der Haupt-Thread-Warteschlange planen, Es könnte also etwas mit Ihrem Problem zu tun haben. Nichtsdestoweniger ist Ihre Verwendung der KVC-Methoden beängstigend, und Sie sollten darüber nachforschen, bevor Sie überhaupt/willChangeValueForKey verwenden. Ich frage mich auch, wenn Sie die Änderungen aus dem Hintergrundkontext in den mainThread/GUI Kontext schieben. – stevesliva

+0

@stevesliva Danke für Ihre Kommentare. Ich merke, dass ich meinen Code kopiert und eingefügt habe, als ich KVO zufällig getestet habe (kranke Studie). Ich habe KVO auf arrangedObjects verwendet (ohne Erfolg). Ich sehe jetzt, dass mein outlineView-Delegat abstürzt, während ich Entitäten lösche, besonders wenn ich eine Entität lösche, bevor ich ihre untergeordneten Elemente lösche, und die outlineView versucht, ein nicht zugeordnetes Objekt zu aktualisieren. Wenn Sie Vorschläge für Best Practices zum Zurücksetzen einer Tabellenansicht oder einer Outline-Ansicht haben, die von Core Data gesteuert wird, wäre das großartig. Ich habe dieses Problem gegooglet, kann aber keine guten Beispiele finden, wie man eine Core Data Driven Ansicht zurücksetzt. –

Antwort

1

Wenn Sie dies erneut betrachten, haben Sie alle Objekte eines Typs in performBlockAndWait abgerufen - dies blockiert den Hauptthread, weil Sie mainQueueConcurrency haben und Sie die andWait-Version von performBlock verwendet haben.

Anschließend löschen Sie jedes Objekt einzeln. Diese Objekte befinden sich in einer Baumdatenstruktur mit einem angehängten Konturansicht (siehe die KVO-Meldungen in der Stapelverfolgung). Diese Objekte haben zu viele Beziehungen, die durch Kerndaten aufrechterhalten werden müssen, verdammt, Sie könnten sogar eine kaskadierende Löschregel haben. (Siehe propagateDelete und maintainInterRelationship in der Stack-Trace) In jedem Fall beginnen Sie anzufragen, dass sowohl die Datenquelle als auch die View im Hauptthread viel Arbeit machen. Sie könnten versuchen, ein untergeordnetes MOC mit privateQueueConcurrency zu verwenden, wenn Sie alle Objekte im Hintergrund iterieren möchten.

Aber wie die Kommentare angezeigt:

NSManagedObjectContext des reset definitiv Speicher freigibt, und es ist in Ordnung für das, was Sie hier tun wollen: alles weg blasen.

Es stellt sich jedoch die Frage, warum Sie das Modell aus dem Speicher auf der Festplatte laden.

Wenn Sie möchten, Core-Daten, aber keine Persistenz zwischen den Zeiten, die Sie das Programm ausführen, können Sie die persistentStoreCoordinator mit einem Speicher von NSInMemoryStoreType initialisieren, anstatt es auf eine Datei URL verweisen.

+0

Ich wusste nicht über den NSInMemoryStoreType und ich verwende nur Core-Daten als "In Memory" (nicht Persistenz), also ist dies ein guter Tipp! Vielen Dank! –

+0

Ich habe es kürzlich zu Testzwecken vorgeschlagen ... Sie könnten Komponententests schreiben, die In-Memory-Speicher erstellen und sie wegwerfen, ohne einen Speicherort auf der Festplatte für Ihren Testspielplatz zu finden. Aber in diesem Fall passt es auch funktional. – stevesliva