usar tutorial porque persistencia efecto datos data apple ios core-data swift3 tableview nsfetchedresultscontroller

ios - tutorial - Uso de 2 FRC con una TableView y configuración de FRCDelegate



swift 4 core data tutorial (0)

Encontré este enlace de la pregunta posterior, y he hecho mi mejor esfuerzo para convertirlo de Obj-C a Swift. Cuando agregué una nueva Entidad e intenté guardarla en CoreData, la aplicación se bloquea y resalta esta línea:

modifiedIndexPath = NSIndexPath(row: (indexPath?.row)!, section: 0)

El error en verde detrás de esto es el siguiente: Thread 1; EXC_BREAKPOINT (code=1, subcode=0x100008b118) Thread 1; EXC_BREAKPOINT (code=1, subcode=0x100008b118) . No tengo idea de lo que esto significa, y el panel de salida solo muestra (llbd) en verde también.

EDITAR - Me di cuenta de que la aplicación está fallando porque indexPath? .row está devolviendo nulo. Simplemente no sé por qué está volviendo nulo.

Mi VC tiene 2 secciones configuradas así:

func numberOfSections(in tableView: UITableView) -> Int { return 2 }

Y el título para el encabezado se establece así:

// set the titles of the tables func tableView( _ tableView : UITableView, titleForHeaderInSection section: Int)->String? { switch(section) { case 0: if(positiveFetchedResultsController.fetchedObjects!.count == 0){ return nil } else{ return "Owes you:" } case 1: if(negativeFetchedResultsController.fetchedObjects!.count == 0){ return nil } else{ return "You owe:" } default :return nil } }

Así es como estoy creando mis dos RFCs

override func viewWillAppear(_ animated: Bool) { // load the data let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest() fetchRequest.predicate = NSPredicate(format:"[email protected] >= 0") let sort = NSSortDescriptor(key: #keyPath(Person.name), ascending: true) fetchRequest.sortDescriptors = [sort] positiveFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.managedContext, sectionNameKeyPath: nil, cacheName: nil) do{ try positiveFetchedResultsController.performFetch() }catch let error as NSError{ print("Fetching error: /(error), /(error.userInfo)") } let negativFetchRequest: NSFetchRequest<Person> = Person.fetchRequest() negativFetchRequest.predicate = NSPredicate(format:"[email protected] < 0") let negativeSort = NSSortDescriptor(key: #keyPath(Person.name), ascending: true) negativFetchRequest.sortDescriptors = [negativeSort] negativeFetchedResultsController = NSFetchedResultsController(fetchRequest: negativFetchRequest, managedObjectContext: coreDataStack.managedContext, sectionNameKeyPath: nil, cacheName: nil) do{ try negativeFetchedResultsController.performFetch() }catch let error as NSError{ print("Fetching error: /(error), /(error.userInfo)") } positiveFetchedResultsController.delegate = self negativeFetchedResultsController.delegate = self print("/(positiveFetchedResultsController.fetchedObjects!.count) positive fetch count") //print("/(positiveFetchedResultsController.fetchedObjects![0].statement!.count) positive statements count") print("/(negativeFetchedResultsController.fetchedObjects!.count) negative fetch count") //print("/(negativeFetchedResultsController.fetchedObjects![0].statement!.count) negative statements count") }

Aquí está el código de delegado de FRC que convertí de la publicación anterior:

extension ViewController: NSFetchedResultsControllerDelegate { func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { tableView.beginUpdates() } func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { var modifiedIndexPath = IndexPath() var modifiedNewIndexPath = IndexPath() if(controller == positiveFetchedResultsController){ modifiedIndexPath = IndexPath(row: (indexPath?.row)!, section: 0) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 0) } if(controller == negativeFetchedResultsController){ modifiedIndexPath = IndexPath(row: (indexPath?.row)!, section: 1) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 1) } switch type { case .insert: //tableView.insertRows(at: [newIndexPath!], with: .automatic) tableView.insertRows(at: [modifiedNewIndexPath as IndexPath], with: .automatic) case .delete: //tableView.deleteRows(at: [indexPath!], with: .automatic) tableView.deleteRows(at: [modifiedIndexPath as IndexPath], with: .automatic) case .update: tableView.reloadRows(at: [modifiedIndexPath as IndexPath], with: .automatic) case .move: //tableView.deleteRows(at: [indexPath!], with: .automatic) //tableView.insertRows(at: [newIndexPath!], with: .automatic) tableView.deleteRows(at: [modifiedIndexPath as IndexPath], with: .automatic) tableView.insertRows(at: [modifiedNewIndexPath as IndexPath], with: .automatic) } } func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { tableView.endUpdates() }

}

EDITAR Parece que IndexPath.row es return nil para indexPath y newIndexPath. Traté de evitar que esto sucediera con este código, pero no sé si voy en la dirección correcta con este proceso de pensamiento:

print("/(indexPath?.row) is the index row number") print("/(newIndexPath?.row) is the NEW index row number") if(controller == self.positiveFetchedResultsController){ if(indexPath?.row == nil) { modifiedNewIndexPath = IndexPath(row: 0, section: 0) modifiedNewIndexPath = IndexPath(row: 0, section: 0) } else{ modifiedIndexPath = IndexPath(row: indexPath!.row, section: 0) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 0) } } if(controller == negativeFetchedResultsController){ if(indexPath?.row == nil) { modifiedIndexPath = IndexPath(row: 0, section: 1) modifiedNewIndexPath = IndexPath(row: 0, section: 1) } else{ modifiedIndexPath = IndexPath(row: indexPath!.row, section: 1) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 1) } }

Y aquí es cómo estoy tratando de guardar mis datos:

/* STEP 2 - Check to see if that persons names was already used */ let personFetchRequest: NSFetchRequest<Person> = Person.fetchRequest() personFetchRequest.predicate = NSPredicate(format: "name == %@", name.text!) do{ let results = try coreDataStack.managedContext.fetch(personFetchRequest) print("/(results.count) this is the results count for the predicate") guard results.count == 0 else{ // print("The Same Name is Used") warningText = "You already used that name." warningMessage() return } /* STEP 3 - Use the name that was typed in */ print("You can use that name") //let personEntity = NSEntityDescription.entity(forEntityName: "Person", in: coreDataStack.managedContext) let person = Person(entity: Person.entity(), insertInto: coreDataStack.managedContext) person.name = name.text /* STEP 4 - Save the data */ coreDataStack.saveContext() self.dismiss(animated: true, completion: {}); }catch{ print("Error") }

Parece que se bloquea justo después de esta declaración de impresión

print("You can use that name")

No puedo guardar en CoreData, y no estoy seguro de por qué.

EDITAR Esto parece haber solucionado mi problema, todavía estoy probando, pero parece estar funcionando.

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { var modifiedIndexPath = IndexPath() var modifiedNewIndexPath = IndexPath() print("/(indexPath?.row) is the index row number") print("/(newIndexPath?.row) is the NEW index row number") if(controller == self.positiveFetchedResultsController){ if(indexPath?.row == nil) { modifiedNewIndexPath = IndexPath(row: 0, section: 0) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 0) } else if(newIndexPath?.row == nil){ modifiedIndexPath = IndexPath(row: indexPath!.row, section: 0) modifiedNewIndexPath = IndexPath(row: 0, section: 0) } else{ modifiedIndexPath = IndexPath(row: indexPath!.row, section: 0) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 0) } } if(controller == negativeFetchedResultsController){ if(indexPath?.row == nil) { modifiedIndexPath = IndexPath(row: 0, section: 1) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 1) } else if(newIndexPath?.row == nil) { modifiedIndexPath = IndexPath(row: indexPath!.row, section: 1) modifiedNewIndexPath = IndexPath(row: 0, section: 1) } else{ modifiedIndexPath = IndexPath(row: indexPath!.row, section: 1) modifiedNewIndexPath = IndexPath(row: (newIndexPath?.row)!, section: 1) } } print("/(indexPath?.row) is the index row number") print("/(newIndexPath?.row) is the NEW index row number") switch type { case .insert: print("/(newIndexPath?.row) is the NEW index row number") // tableView.insertRows(at: [newIndexPath!], with: .automatic) tableView.insertRows(at: [modifiedNewIndexPath as IndexPath], with: .automatic) case .delete: //tableView.deleteRows(at: [indexPath!], with: .automatic) tableView.deleteRows(at: [modifiedIndexPath as IndexPath], with: .automatic) case .update: tableView.reloadRows(at: [modifiedIndexPath as IndexPath], with: .automatic) case .move: //tableView.deleteRows(at: [indexPath!], with: .automatic) //tableView.insertRows(at: [newIndexPath!], with: .automatic) tableView.deleteRows(at: [modifiedIndexPath as IndexPath], with: .automatic) tableView.insertRows(at: [modifiedNewIndexPath as IndexPath], with: .automatic) } }

Parece que se asignan sentencias if / else para este tipo de cosas. Esperando que alguien tenga una versión más limpia de esto.