Valor de relación cero para la ruta de key de nombre de sección en nsfetchedresultscontroller

Para un model de datos centrales en el que EntityA tiene una relación de muchos a uno con EntityB, quiero crear una list de objects de EntityA, orderados por el nombre de la entidad con la que están relacionados. Normalmente para hacer esto, configuraría la request de obtención de este modo:

if (_fetchedResultsController != nil) { return _fetchedResultsController; } NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 

Luego establecería los valores de mi request: (en este caso, es una list de plantas clasificadas por nombre de especie. Algunas plantas no tienen ningún set de especies).

 NSEntityDescription *entity = [NSEntityDescription entityForName:@"Plant" inManagedObjectContext:self.managedObjectContext]; NSSortDescriptor *sortDescriptorOne = [[NSSortDescriptor alloc] initWithKey:@"species.name" ascending:YES]; NSString *sectionKeyPath = @"species.name"; 

Luego termino con las cosas habituales:

 [fetchRequest setEntity:entity]; // Set the batch size to a suitable number. [fetchRequest setFetchBatchSize:20]; NSArray *sortDescriptors = @[sortDescriptorOne]; [fetchRequest setSortDescriptors:sortDescriptors]; NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:sectionKeyPath cacheName:@"plantsCache"]; aFetchedResultsController.delegate = self; self.fetchedResultsController = aFetchedResultsController; [NSFetchedResultsController deleteCacheWithName:@"plantsCache"]; NSError *error = nil; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return _fetchedResultsController; 

Pero el resultado que obtengo no funciona para mí porque la relación es opcional. Entonces, algunos de EntityA tienen una relación con EntityB y otros no. El controller de resultados no parece saber qué hacer cuando el valor de la relación de EntityA es nulo.

¿Alguna sugerencia de lo que puedo hacer para continuar haciendo secciones usando el valor de la relación, pero permitiendo que algunos objects tengan cero para ella?

Configura una propiedad transitoria en Plant así:

 -(NSString*)speciesName { return self.species ? self.species.name : @""; } 

Ahora puede usar speciesName como sectionNameKeyPath .

Entró en esto con Swift 3.0. Tenía dos entidades EntityA y EntityB, a las que EntityA por lo general pertenece (tiene un puntero a) alguna EntityB, pero también puede ser no propietaria.

La solución Swift fue agregar una extensión a EntityA que devuelve una cadena vacía si se detecta una condición nula.

 extension Note { var bookTitleOrNil : String { if let bookTitle = self.book?.title { return bookTitle } return "" } } 

A continuación, reemplace los siguientes en la construcción del fetchRequestController (FRC):

 let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataManager.managedObjectContext, sectionNameKeyPath: "book.title", cacheName: nil) 

Con el uso de la nueva extensión para sectionNameKeyPath:

 let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataManager.managedObjectContext, sectionNameKeyPath: "bookTitleOrNil", cacheName: nil) 

Luego, al generar encabezados para las diferentes secciones, utilicé lo siguiente:

 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { let useIndexPath = IndexPath(row: 0, section: section) // Get first item in section (all notes in a section point to same book) let note = frc.object(at: useIndexPath) if let bookTitle = note.book?.title { return bookTitle } else { return "Unlinked" } } 

De modo que las notas salen orderadas primero por el libro al que pertenecen como se muestra en el encabezado de la sección (aunque las notas que no pertenecen a ningún libro salen orderadas primero bajo el encabezado "Desvinculado").

Además, al configurar la sorting en fetchRequest del FRC, uno debe configurar el descriptor de sorting primaria para usar book.title y luego cualquier sorting adicional, como el título de la nota.

 let sortDescriptor1 = NSSortDescriptor(key: "book.title", ascending: true) let sortDescriptor2 = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2] 

Por supuesto, también se puede diseñar la aplicación para que una nota siempre pertenezca a un libro mediante cheques adicionales cuando se cree una nota y evitar así todo el caso.