1

Ниже приведена ссылка на скачивание упрощенной версии моего приложения с той же проблемой. Кнопка «Добавить» наверху добавляет новую запись, которая задается с именем = 1, qty = 1 и секцией = 1. Выбор ячейки увеличивает их все до следующего числа. Вы можете видеть, что и имя, и количество обновлений, но раздел никогда не обновляется, пока вы не покинете приложение и не запустите его снова. DropBox Download LinkСобытие обновления раздела, которое не вызывается из связанного объекта в swift

У меня есть следующие настройки отношения в CoreData:

enter image description here

В В моем TableViewController, я создаю мой FetchRequestController (FRC) со следующим кодом:

func fetchRequest() -> NSFetchRequest { 

    let fetchRequest = NSFetchRequest(entityName: "Items") 
    let sortDesc1 = NSSortDescriptor(key: "catalog.sections.section", ascending: true) 
    let sortDesc2 = NSSortDescriptor(key: "isChecked", ascending: true) 
    let sortDesc3 = NSSortDescriptor(key: "catalog.name", ascending: true) 
    fetchRequest.sortDescriptors = [sortDesc1, sortDesc2, sortDesc3] 

    return fetchRequest 

} 

func getFCR() -> NSFetchedResultsController { 

    frc = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "catalog.sections.section" , cacheName: nil) 

    return frc 

} 

Итак, как показано, я предварительно формирую запрос на выборку в Entity Item и сортировку по атрибутам как в объектах Catalog, так и в разделах. И, в частности, к моей проблеме, у меня есть секция в моем frc как атрибут раздела в Sections Entity (который связан через Entity Catalog).

Когда я обновляю различные части пункта или каталога, я вижу обновление ячейки таблицы правильно (то есть событие didChangeObject называется)

Но если изменить раздел она никогда не обновляет, если я полностью обратно из таблицу, а затем повторно введите ее. (т. е. событие didChangeSection никогда не вызывается, даже если секция меняется)

Ниже приведен код, который я использую для редактирования ранее существующей записи элемента.

func editItem() { 

    let item: Items = self.item! 

    item.qty = Float(itemQty.text!) 

    item.catalog!.name = Util.trimSpaces(itemName.text!) 
    item.catalog!.brand = Util.trimSpaces(itemBrand.text!) 
    item.catalog!.qty = Float(itemQty.text!) 
    item.catalog!.price = Util.currencyToFloat(itemPrice.text!) 
    item.catalog!.size = Util.trimSpaces(itemSize.text!) 
    item.catalog!.image = UIImageJPEGRepresentation(itemImage.image!, 1) 

    if (self.section != nil) { 
     item.catalog!.sections = self.section 
    } 

    do { 
     try moc.save() 
    } catch { 
     fatalError("Edit Item save failed") 
    } 

    if (itemProtocal != nil) { 
     itemProtocal!.finishedEdittingItem(self, item: self.item!) 
    } 

} 

Просто к сведению, когда я добавляю в новой записи в пункт Entity, события didChangeObject и didChangeSection оба правильно называется. Только при их редактировании происходит передача пропускаемого или пропущенного элементаChangeSection.

Просто для завершения, ниже мой код, который я использую для didChangeObject и didChangeSection.

func controllerWillChangeContent(controller: NSFetchedResultsController) { 

    tableView.beginUpdates() 

} 

func controllerDidChangeContent(controller: NSFetchedResultsController) { 

    tableView.endUpdates() 

} 

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { 

    switch type { 
    case NSFetchedResultsChangeType.Update: 
     self.tableView.reloadSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic) 
    case NSFetchedResultsChangeType.Delete: 
     self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic) 
    case NSFetchedResultsChangeType.Insert: 
     self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic) 
    case NSFetchedResultsChangeType.Move: 
     self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic) 
     self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic) 
    } 

} 

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 

    switch type { 
    case NSFetchedResultsChangeType.Update: 
     self.tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic) 
    case NSFetchedResultsChangeType.Delete: 
     self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic) 
    case NSFetchedResultsChangeType.Insert: 
     self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Fade) 
    case NSFetchedResultsChangeType.Move: 
     self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic) 
     self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic) 
    } 

} 

Когда я гугле этот вопрос, я обнаружил, что другие были проблемы, подобные этим, и это, кажется, особенность (или ошибка) КОП и как Xcode обрабатывает отношения. В принципе, frc наблюдает только за объектом Entity, а когда объект Section изменяется, он не регистрируется с помощью frc. Люди также предлагали различные хаки, но пока никто из них не работает для меня. Примеры - сделать что-то вроде этого item.catalog.sections = item.catalog.sections Ни один из примеров не имел ключ раздела как связанный объект, поэтому я не уверен, что именно поэтому они не работают для меня.

Итак, мой вопрос в том, есть ли способ сказать didChangeSection для выполнения и отправить его надлежащий NSFetchedResultsChangeType? Или еще лучше, есть ли какой-то способ «побудить» frc заметить, что происходит в объекте раздела, связанного с объектом объекта через Entity Catalog.

ответ

2

После игры с этим немного, кажется, didChangeSection только уволен, если первая связь с именем в sectionNameKeyPath непосредственно модифицирован (то есть. В этом случае, если вы создаете новый Catalog связанный с правильной секции, и установите item.catalog = newCatalog). Но я думаю, что это слишком запутанно, как работа.

Одним из решений было бы изменить ваш FRC для получения объектов Catalog вместо Items. Поскольку они отображают один-один, представление таблицы должно сохранять ту же структуру. Основные изменения:

func fetchRequest() -> NSFetchRequest { 

    let fetchRequest = NSFetchRequest(entityName: "Catalog") 
    let sortDesc1 = NSSortDescriptor(key: "sections.section", ascending: true) 
    let sortDesc2 = NSSortDescriptor(key: "name", ascending: true) 
    fetchRequest.sortDescriptors = [sortDesc1, sortDesc2] 

    return fetchRequest 
} 

и

func getFCR() -> NSFetchedResultsController { 

    frc = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "sections.section" , cacheName: nil) 

    return frc 

} 

Затем измените ссылки на frc, чтобы отразить это изменение:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell 
    let catalog: Catalog = frc.objectAtIndexPath(indexPath) as! Catalog 

    cell.nameLbl.text = "Item #\(catalog.name!)" 
    cell.qtyLbl.text = "Qty: \(catalog.items.qty!.stringValue)" 

    return cell 
} 

и

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 

    let catalog: Catalog = frc.objectAtIndexPath(indexPath) as! Catalog 

    var qty: Int = Int(catalog.items.qty!) 
    qty = qty + 1  
    catalog.items.qty = qty 

    var name: Int = Int(catalog.name!) 
    name = name + 1 
    catalog.name = name 

    var sec: Int = Int(catalog.sections.section!) 
    sec = sec + 1 
    var section: Sections? 
    if (checkSectionName(sec, moc: self.moc) == false) { 
     let entityDesc = NSEntityDescription.entityForName("Sections", inManagedObjectContext: self.moc) 
     section = Sections(entity: entityDesc!, insertIntoManagedObjectContext: self.moc) 

     section!.section = sec 
    } else { 
     section = returnSection(sec, moc: self.moc) 
    } 

    catalog.sections = section 

    do { 
     try moc.save() 
    } catch { 
     fatalError("Edit item save failed") 
    } 

} 

Поскольку вы напрямую м одиозное свойство sections объекта catalog, это вызовет метод didChangeSection. Это по-прежнему кажется мне немного взломанным, но поскольку FRC не ведет себя так, как хотелось бы, взлом может быть необходимым злом.

+0

Это сработало отлично! Спасибо за предложение. Я смог реализовать его и в оригинальном приложении. Только другое изменение, которое мне нужно было сделать, это добавить предикат к 'fetchRequest()', поскольку каждый элемент имеет связанный каталог, но не каждый каталог гарантирует наличие связанного элемента. 'let pred = NSPredicate (format:" items! = nil ")' & 'fetchRequest.predicate = pred' Он говорит, что мне нужно подождать 6 часов, прежде чем я смогу наградить награду, но я постараюсь сделать это сегодня вечером. –

1

Я столкнулся с подобной ситуацией, и в итоге я создал второй NSFetchedResultsController для другого типа и просто прослушал его для событий изменений и, при необходимости, обновил свое представление. Не идеальное решение, так как для этого требуется некоторая ручная координация и хранение некоторых метаданных, но она выполняет свою работу.

+0

Это звучит неплохо. Как бы вы использовали оба frc? Или не обязательно использовать их обоих, просто создавайте их, чтобы в контроллере табличного представления одновременно работали два слушателя? Я не уверен, можете ли вы дать мне быстрый пример или описание того, как это будет работать? Я все еще относительно новый и программирующий. Большое вам спасибо. –

+0

Итак, причина, по которой я надеялся на пример того, как это будет работать, я бы предположил, что если бы я поставил второй frc, он зарегистрировал бы изменение пути индекса относительно себя, поэтому, если бы он не имел ту же структуру, что и другой frc он будет сообщать об изменениях относительно себя и сообщать различным разделам/строкам, чтобы обновить, чем то, что у меня есть в первом frc. –

+0

У меня нет примера кода, удобного для этой идеи.Я бы предположил, что вы бы использовали один контроллер для фактического управления таблицей, и вам нужно будет немного поработать, чтобы отслеживать, какие разделы были фактически представлены данными в таблице. Затем вы будете использовать другой контроллер, который извлекает разделы, которые должны быть уведомлены об изменениях в данных раздела, перекрестные ссылки на изменения с разделами, которые вы отслеживали, и выяснить, какие обновления вам нужно внести в таблицу. –

1

Это действительно продолжение ответа от @CharlesA

Как вы нашли FRC ничего, кроме связанного с ним объекта для изменения не наблюдается. Это не особенность или ошибка, это деталь реализации, поскольку она охватывает большой процент использования, а код, необходимый для анализа графика для произвольных изменений глубины, является сложным. В дополнение к этому обратные вызовы делегатов для единого изменения, объединенного в контекст, могут быть чрезвычайно сложными и практически невозможно применить к таблице с анимацией.

Итак, вам действительно нужно изменить свой подход. Ответ от Чарльза с использованием второго FRC требует, чтобы второй FRC использовался, чтобы проинструктировать первый FRC повторно выполнить его выборку и полностью перезагрузить представление таблицы. Вам нужно повторно выполнить выборку, потому что иначе ваш источник данных ошибочен, и нет другого способа его обновления. Технически вы можете попытаться применить изменения к таблице с анимацией, в зависимости от того, что вы знаете/гарантируете, как сделаны изменения и сохранены в контексте, в котором он может работать. Например, если пользователь может изменять только 1 секцию за раз, и она автоматически сохраняется. И что никакие составные изменения не выполняются в фоновом потоке.

Ответ от @pbasdf также является подходящей альтернативой, но он по-прежнему будет иметь дело только с изменениями отношений, а не изменениями значений в объектах в конце этих отношений - это ключевое различие, которое необходимо понять и оцените при использовании FRC.