0

I haben einen Kern-Daten-Anwendung, die ohne Absturz läuft, wenn ich eine durchführen fetch innen viewDidLoad wie folgt aus:Coredata Fetch Crashes verwendet, wenn mit dispatch_async

- (void) performCoreDataFetch { 
    NSError *error; 
    if (![[self fetchedResultsController] performFetch:&error]) { 
     exit(-1); // Fail 
    } 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self performCoreDataFetch]; 
} 

Das einzige Problem bei der obigen Weise fetch der Durchführung ist, wenn Die Daten, die zurückgegeben werden sollen, sind groß, es friert die App für ein paar Sekunden ein (aber gibt das korrekte Ergebnis ohne Absturz jedes Mal zurück), um zu vermeiden, dass ich dispatch_async (Code unten) benutze und [self performCoreDataFetch] darin anrufe.

Aber wenn ich das gleiche [self performCoreDataFetch] laufen innerhalb dispatch_sync innerhalb viewDidLoad, wie unten ,:

gezeigt
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self performCoreDataFetch]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self.tableView reloadData]; 
     }); 
    }); 

Aufruf [self performCoreDataFetch] innerhalb dispatch_async stürzt die zufällig app "-[NSFetchRequest fetchLimit]: message sent to deallocated instance"

sagen Meine fetchedResultsController-Methode sieht wie folgt aus:

- (NSFetchedResultsController *)fetchedResultsController { 
    if (fetchedResultsController != nil) { 
     return fetchedResultsController; 
    } 

    // Create and configure a fetch request with the Organization entity 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    request.entity = [NSEntityDescription entityForName:@"Organization" inManagedObjectContext:managedObjectContext]; 
    request.fetchBatchSize = 20; 

    // create sortDescriptor array 
    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; 
    NSArray *sortDescriptorArray = [NSArray arrayWithObjects:nameDescriptor, nil]; 
    request.sortDescriptors = sortDescriptorArray; 

    NSPredicate *predicate = nil; 

    predicate = [NSPredicate predicateWithFormat:@"state LIKE %@", filterByState]; 
    [request setPredicate:predicate]; 

    // Create and initialize the fetchedResultsController 
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc ] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:@"uppercaseFirstLetterOfName" cacheName:nil]; 

    self.fetchedResultsController = aFetchedResultsController; 
    fetchedResultsController.delegate = self; 

    // Memory management 
    filterByState = nil; 
// [sortDescriptorArray release]; 
    [nameDescriptor release]; 
// [predicate release]; 
    [request release]; 
    [aFetchedResultsController release]; 

    return fetchedResultsController; 

} 
+0

Was versuchen Sie zu erreichen? Sie sollten die Methode "performFetch" nicht selbst aufrufen müssen ... – Mundi

+0

Ohne performFetch ist mir keine andere Möglichkeit bekannt, einen Core Data Fetch auszuführen. – Stealth

+0

Was versuchst du zu erreichen? Wenn Sie den abgerufenen Results-Controller langsam initialisieren, wird der Abruf dort durchgeführt, ohne dass Sie 'performFetch' selbst aufrufen müssen. Nochmal, was versuchst du mit dem Fetch zu machen? – Mundi

Antwort

3

Core-Daten sind nicht Thread-sicher, wenn Sie einen Abruf für einen abgerufenenResultsController durchführen. Dies ist sinnvoll, da der abgerufeneResultsController die Datenquelle Ihrer Benutzeroberfläche ist. Anstatt einen Fetch durchzuführen, setzen Sie Ihren fetchedResultsController auf nil und laden Sie Ihr TableView neu.

+0

Willst du damit sagen, dass ich innerhalb meiner nsfetchedResultsController-Methode immer anfangen soll, indem ich den holeResultsController auf null setze? – Stealth

+0

Nein. Sie müssen es auf "Null" setzen, wenn Sie Ihre Tabelle aktualisieren müssen. Das Tabellenupdate ruft automatisch Ihre Methode 'fetchedResultsController' auf, die langsam eine neue Methode erstellt. (Sehen Sie sich die Methode an und sehen Sie, wie sie funktioniert.) – Mundi

1

Kerndaten sind nicht Thread speichern. Um genauer zu sein, ist der NSManagedObjectContext nicht sicher. Alle NSManagedObject gehören zu einem bestimmten NSManagedObjectContext und sind nicht austauschbar.

Pre IOS 5 müssen Sie wirklich sehr komplizierte Methode setzen. Grundsätzlich jeder Thread benötigen sie eigene NSManagedContext

Nach IOS5 ist, können Sie tun:

__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

Dann können Sie

[__managedObjectContext performBlock ^{ 
    //Some really long operation 
}] 

auf jedem Thread tun, die nicht Haupt-Thread ist.

Das wird es auf einem anderen Thread jedoch in einem Thread speichern Weg. Im Grunde werden Core-Daten Ihre Operation in Warteschlangen stellen und sie nacheinander ausführen, um den managedObjectContext für jede Operation zu sperren.