Objetos de Core Data se vuelven nulos

Estoy creando una aplicación de tareas que debería ser compatible con el modo fuera de línea. He usado RestKit para download tareas y mapear eso en los datos Core locales.

Esto funciona bien en modo en línea. Pero en línea hay un problema extraño. Utilizo NSPnetworkingicate para get datos del almacenamiento local. Para esto estoy usando loggings mágicos.

+ (void)getIdeasTasksWithPageNo:(int)pageNo completionHandler:(void (^)(NSArray *, NSError *))completionHandler { NSArray *tasks = [self MR_findAllWithPnetworkingicate:[NSPnetworkingicate pnetworkingicateWithFormat:@"due_date = nil AND user_id = %@", [DBUsers currentUser].id]]; completionHandler(tasks, nil); } 

Y lo llamo así:

 [DBTasks getIdeasTasksWithPageNo:1 completionHandler:^(NSArray *tasks, NSError *error) { if (!error) { [self displayTasksWithResults:tasks forPageNo:1]; } else { NSLog(@"Error is %@", error); } }]; 

Y así es como lo estoy mostrando en UITableView

 -(void)displayTasksWithResults:(NSArray *)tasks forPageNo:(int)pageNo { if (!self.tasksArray) { self.tasksArray = [[NSMutableArray alloc] init]; } else { [self.tasksArray removeAllObjects]; } [self.tasksArray addObjectsFromArray:tasks]; [self.tableview reloadData]; } 

Esto funciona solo por primera vez y todas las tareas se rellenan en UITableView .

El problema es después de que UITableView esté poblado, todos los loggings en self.tasksArray vuelven Null . Si UITableView , las filas de la tabla comienzan a estar vacías.

Pero si self.tasksArray en el método displayTasksWithResults , se imprime perfectamente.

 ( "Title: Task 01", "Title: You've gone incognito. Pages you view in incognito tabs won't stick around in your browser's history, cookie store, or search history after you've closed all of your incognito tabs. Any files you download or bookmarks you create will be kept. ", "Title: Task 06", "Title: Task 04", "Title: Hi", "Title: Task 3", "Title: Task 4", "Title: Hi 4", "Title: hh", "Title: Task 02", "Title: Task 05\n", "Title: Task 4", "Title: Task 5", "Title: Task 2 updated", "Title: Here is a task. ", "Title: Task 03", "Title: Hi 3", "Title: Task 2", "Title: Hi 2", "Title: Testing task email with Idea Task", "Title: Task f6", "Title: 1.117", "Title: Task f5", "Title: Task f12", "Title: Task f4", "Title: Task f3", "Title: 111.0.113", "Title: 111.0.115", "Title: Pages you view in incognito tabs won't stick around in your browser's history, cookie store, or search history after you've closed all of your incognito tabs. Any files you download or bookmarks you create will be kept.", "Title: Task f7", "Title: 1.116", "Title: 1.118", "Title: Going incognito doesn't hide your browsing from your employer, your internet service provider, or the websites you visit. ", "Title: 111.0.111" ) 

Si self.taskArray más adelante, puede estar en el delegado UITableView de UITableView , se imprime como a continuación:

 ( "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)", "Title: (null)" ) 

Creo que esto puede estar relacionado con NSManagedObjectContext , pero no sé cómo solucionarlo.

¡Por favor ayuda!

El problema es que (como escribí en un comentario) que los objects se obtienen en un hilo de background, pero que se utilizan en el hilo principal (UI). Los objects administrados solo pueden "vivir" en el context en el que fueron creados. Si el context se desasigna, los objects aún existen, pero los methods de acceso de properties devuelven nil .

Soluciones posibles:

  • Obtenga los objects en el hilo principal.
  • Utilizar

     NSManagedObject *copy = [[mainContext objectWithID:[object objectID]]; 

    para "copyr" los objects del context de background al context principal. (Quizás MagicalRecord tiene un método de conveniencia.)

  • En lugar de search objects administrados, establezca

     [fetchRequest setResultType:NSDictionaryResultType]; [fetchRequest setPropertiesToFetch:@[@"title", ...]]; 

    para search una variedad de dictionarys con los attributes que le interesan.

Finalmente encontré el motivo de los objects nulos. Estaba llamando a search en segundo plano. Así que Magical Records crea un nuevo context de object gestionado específico para ese hilo, en NSManagedObject+MagicalFinders.m

 + (NSManagedObjectContext *) MR_contextForCurrentThread; { if ([NSThread isMainThread]) { return [self MR_defaultContext]; } else { NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; NSManagedObjectContext *threadContext = [threadDict objectForKey:kMagicalRecordManagedObjectContextKey]; if (threadContext == nil) { threadContext = [self MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]]; [threadDict setObject:threadContext forKey:kMagicalRecordManagedObjectContextKey]; } return threadContext; } } 

Entonces necesitaba copyr objects del context del hilo de background al context del hilo principal. Finalmente encontré la solución aquí y creé mi método de esta manera.

 + (void)backgroundFetchWithPnetworkingicate:(NSPnetworkingicate *)pnetworkingicate completion:(void(^)(NSArray *, NSError *))completion { NSManagedObjectContext *privateContext = [NSManagedObjectContext MR_context]; [privateContext performBlock:^{ NSArray *privateObjects = [self MR_findAllWithPnetworkingicate:pnetworkingicate inContext:privateContext]; NSArray *privateObjectIDs = [privateObjects valueForKey:@"objectID"]; // Return to our main thread dispatch_async(dispatch_get_main_queue(), ^{ NSPnetworkingicate *mainPnetworkingicate = [NSPnetworkingicate pnetworkingicateWithFormat:@"self IN %@", privateObjectIDs]; NSArray *finalResults = [self MR_findAllWithPnetworkingicate:mainPnetworkingicate]; completion(finalResults, nil); }); }]; } 

Ahora solo tengo que llamarlo así:

 [self backgroundFetchWithPnetworkingicate:pnetworkingicate completion:^(NSArray *results, NSError *error) { completionHandler(results, error); }]; 

Supongo que es porque está asignando directamente el valor a la matriz. Intenta asignar valor usando mutablecopy.

 NSArray *tasks = [[self MR_findAllWithPnetworkingicate:[NSPnetworkingicate pnetworkingicateWithFormat:@"due_date = nil AND user_id = %@", [DBUsers currentUser].id]] mutableCopy]; 

He encontrado varios puntos débiles en su código, intente resolverlos:

  1. Nunca pageNo parámetro pageNo en tu + (void)getIdeasTasksWithPageNo:(int)pageNo completionHandler:(void (^)(NSArray *, NSError *))completionHandler

  2. Siempre pasa nil para el parámetro de error en el método anterior

  3. ¿Cuál es el propósito de eliminar objects de array [self.tasksArray removeAllObjects]; ? (en primer lugar tratar de comentar esta línea tal vez esta es la razón)

En primer lugar, compruebe si está utilizando CoreData en una circunstancia de varios subprocesss, si lo hace, puede necesitar agregar algún código de queue de despacho para asegurarse de que su código CoreData se ejecute solo en un subprocess. En segundo lugar, llame a algunos otros methods de su matriz de resultados para ver si el NSManagedObject está en un estado de falla, llamando a algunos methods, lo hará search.