ios - Core-Data executeFetchRequest congela la aplicación en un hilo de fondo
multithreading nsmanagedobjectcontext (1)
Tengo un saveMOC
que es el padre directo de un mainMOC
, y necesito buscar en línea otro tmpMOC
para no bloquear mi UI mientras obtengo un montón de registros de Internet.
Mi aplicación se congela. Podría limitarlo a este mismo punto:
fetchedItems = [tmpMOC executeFetchRequest:fetchRequest error:&error];
Intenté adjuntar esto dentro de dispatch_sync
, [moc.parentcontext.parentcontext.persistentStoreCoordinator lock/unlock]
, [whatevermoc performBlockAndWait]
...
También trato de buscar el _mainMOC
... De ninguna manera ...
Entiendo que executeFetchRequest
no es seguro para subprocesos, entonces, ¿cómo bloqueo lo que necesito bloquear para asegurarme de que no estoy insertando un doble?
¿Alguien podría ayudar?
ACTUALIZACIÓN (1) instanciación _saveMOC
en AppDelegate:
- (NSManagedObjectContext *)managedObjectContext
{
if (_mainMOC != nil) {
return _mainMOC;
}
if (_saveMOC == nil) {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_saveMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_saveMOC setPersistentStoreCoordinator:coordinator];
[_saveMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
}
}
if (_mainMOC == nil) {
_mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainMOC setParentContext:_saveMOC];
[_mainMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveContextChanges:) name:NSManagedObjectContextDidSaveNotification object:_mainMOC];
Creación de tempoMOC en MainViewController:
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = _mainMOC;
[temporaryContext performBlock:^{ //AndWait
NSError *error=nil;
Feed *feed=(Feed *)[temporaryContext existingObjectWithID:feedID error:&error];
//...
[RSSParser parseRSSFeedForRequest:req success:^(NSArray *feedItems)
{
NSLog(@"[MasterViewController::fetchPosts] inserting %d Posts.../OK", (int)[feedItems count]);
feed.valid = [NSNumber numberWithBool:YES];
for(RSSItem *i in feedItems)
{
[self createPostInFeed:feed withTitle:i.title withContent:(i.content?i.content:i.itemDescription) withURL:[i.link absoluteString] withDate:(i.pubDate?i.pubDate:[NSDate date]) inMOC:temporaryContext];
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"NewPostsFetched" object:f];
Luego, la congelación ocurre en createPostInFeed
:
// @synchronized(fetchRequest) { // THIS DOESN''T CHANGE ANYTHING
// [moc.persistentStoreCoordinator lock]; // THIS NEITHER
NSArray *fetchedItems;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *ent = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:moc];
fetchRequest.entity = ent;
fetchRequest.propertiesToFetch = [NSArray arrayWithObjects:@"title", @"url", @"feed.name", nil];
[fetchRequest setResultType:NSDictionaryResultType];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"title == %@ AND url == %@ AND feed.rss == %@", title, url, feed.rss];
NSError *error = nil;
fetchedItems = [moc executeFetchRequest:fetchRequest error:&error]; // FREEZES HERE
// [moc.persistentStoreCoordinator unlock]; // THIS DOESN''T CHANGE ANYTHING
// } // Synchronized neither...
Actualización (2): esto es lo que ve Time Profiler.
Actualización (3): Bloque editado:
NSUInteger fetchedItems;
NSString *feedRSS=feed.rss;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *ent = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:moc];
fetchRequest.entity = ent;
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"title == %@ AND url == %@ AND feed.rss == %@", title, url, feedRSS];
NSLog(@"MainViewController::createPostInFeed> Before fetchRequest for %@ (%@)", title, url);
NSError *error = nil;
fetchedItems = [moc countForFetchRequest:fetchRequest error:&error];
NSLog(@"MainViewController::createPostInFeed> After fetchRequest for %@ (%@)", title, url); // THIS NSLOGGING NEVER HAPPENS
Actualización (4): Nueva foto de perfil con el árbol de llamadas invertido.
¿Cuál es tu objetivo con createPostInFeed
? Usted muestra que está buscando, pero ¿qué hace con esa búsqueda? ¿Es esto una verificación "insertar o actualizar"? o es solo una prueba de "insertar u omitir"?
Cualquier búsqueda bloqueará NSPersistentStoreCoordinator
y hará que su aplicación se bloquee mientras se realiza la búsqueda. Hay formas de mitigar eso:
- Ejecutar instrumentos
- Haga sus compras más eficientes
- Si no necesita objetos (en una prueba de inserción o de omisión), haga una cuenta en su lugar
- Busque en una cola de fondo y asegúrese de que su MOC principal tenga todos los objetos que necesita para evitar un bloqueo
¿Qué te muestra tu perfil de instrumentos?
¿Qué hace createPostInFeed
con los resultados de esa búsqueda?