2016-05-24 15 views
0

CoreDataと関連するエンティティのセクションに問題があります。私の問題を示すために、私はできるだけ簡単なバージョンのアプリケーションを作った。これは、ファイルをダウンロードしたい場合、そのファイルへのリンクです。 https://www.dropbox.com/s/y7gcpu7qq2mnrye/Sample%20List%20App.zip?dl=0didChangeSectionを呼び出してセクションの更新を強制的に行う方法

これは単なるテーブルビューで、プラスボタンを押すと、数量が1、名前が1、セクションが1の新しい項目が追加されます。次に、セルをクリックするとすべてが増えます。名前と数量の両方がうまく更新されていますが、セクションは決して更新されません。これは、frcがセクションテーブルの変更を追跡していないが、カタログまたは項目テーブルに問題がないためと思われる。私は、アプリケーションを終了し、再び起動すると、セクションが正しく読み込まれます。ここに私の現在のエンティティと(シンプルなアプリの)関係

enter image description here

は以下tableviewcontrollerからのコードです。この小さなで遊んでたら、sectionNameKeyPathにという名前の最初の関係が直接すなわち(変更された場合。この場合には、あなたが正しいセクションにリンクされている新しいCatalogを作成する場合didChangeSectionのみが発射される

import UIKit 
import CoreData 

class TableViewController: UITableViewController, NSFetchedResultsControllerDelegate { 

// MARK: - Constants and Variables 

let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext 
var frc: NSFetchedResultsController = NSFetchedResultsController() 

// MARK: - App loading Functions 

override func viewDidLoad() { 
    super.viewDidLoad() 

    frc = getFCR() 
    frc.delegate = self 

    do { 
     try frc.performFetch() 
    } catch { 
     print("Failed to perform inital fetch") 
    } 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 

// MARK: - Outlets and Actions 

@IBAction func addItemPress(sender: UIBarButtonItem) { 

    var entityDesc = NSEntityDescription.entityForName("Items", inManagedObjectContext: self.moc) 
    let item = Items(entity: entityDesc!, insertIntoManagedObjectContext: self.moc) 

    item.qty = 1 

    entityDesc = NSEntityDescription.entityForName("Catalog", inManagedObjectContext: self.moc) 
    let catalog = Catalog(entity: entityDesc!, insertIntoManagedObjectContext: self.moc) 

    catalog.name = 1 

    var section: Sections? 
    if (checkSectionName(0, moc: self.moc) == false) { 
     entityDesc = NSEntityDescription.entityForName("Sections", inManagedObjectContext: self.moc) 
     section = Sections(entity: entityDesc!, insertIntoManagedObjectContext: self.moc) 

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

    item.catalog = catalog 
    item.catalog!.sections = section 

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

// MARK: - Table view data source 

override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 

    if let sections = frc.sections { 
     return sections.count 
    } 

    return 0 
} 

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

    if let sections = frc.sections { 
     let currentSection = sections[section] 
     return currentSection.numberOfObjects 
    } 

    return 0 
} 

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

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

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

    return cell 
} 

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 

    if let sections = frc.sections { 
     let currentSection = sections[section] 
     return "Section \(currentSection.name)" 
    } 

    return nil 
} 

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.moveRowAtIndexPath(indexPath!, toIndexPath: newIndexPath!) 
    } 
} 

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

    let item: Items = frc.objectAtIndexPath(indexPath) as! Items 
    var qty: Int = Int(item.qty!) 
    qty = qty + 1 

    item.qty = qty 

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

    item.catalog!.name = name 

    var sec: Int = Int(item.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) 
    } 

    item.catalog!.sections = section 

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

} 

func fetchRequest() -> NSFetchRequest { 

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

    return fetchRequest 

} 

func getFCR() -> NSFetchedResultsController { 

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

    return frc 

} 

func checkSectionName(sectionName: NSNumber, moc: NSManagedObjectContext) -> Bool { 

    var exists: Bool = false 

    let fetchReq = NSFetchRequest(entityName: "Sections") 
    let pred = NSPredicate(format: "section == %@", sectionName) 
    fetchReq.predicate = pred 

    do { 
     let check = try moc.executeFetchRequest(fetchReq) 
     for rec in check { 
      if let name = rec.valueForKey("section") { 
       if (name as! NSNumber == sectionName) { 
        exists = true 
       } 
      } 
     } 
    } catch { 
     fatalError("Failed fetching records when checking if List name already exists") 
    } 

    return exists 

} 

func returnSection(sectionName: NSNumber, moc: NSManagedObjectContext) -> Sections { 

    let fetchReq = NSFetchRequest(entityName: "Sections") 
    let pred = NSPredicate(format: "section == %@", sectionName) 
    fetchReq.predicate = pred 

    do { 
     let check = try moc.executeFetchRequest(fetchReq) 
     return check.first! as! Sections 
    } catch { 
     fatalError("Failed fetching records to return section") 
    } 
} 

} 

答えて

1

です、およびitem.catalog = newCatalogを設定します)。しかし、私はそれが回避策として複雑すぎると思います。

解決策の1つはItemsの代わりにCatalogオブジェクトを取得するようにFRCを変更することです。それらは1対1をマッピングするので、テーブルビューは同じ構造を保持する必要があります。主な変更は以下のとおりです。

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") 
    } 

} 

をあなたが直接であるため、 m catalogオブジェクトのsectionsプロパティを省略すると、didChangeSectionメソッドがトリガされます。

+0

あなたの質問に引用されている例からあなたの現実世界の問題にうまく翻訳できないかもしれない、醜い解決策です。私はそれが助けて欲しい – pbasdf

+0

これは本当に良いアイデアです!私は今夜​​家に帰るときにそれを撃つつもりです。ありがとう –

+0

爆笑、あなたもこの1つに投稿する必要があります、それは賞金がある場所です。 http://stackoverflow.com/questions/37328774/section-update-event-not-being-called-from-related-entity-in-swift –

関連する問題