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.