核心数据一对多关系不存储其数据

Posted

技术标签:

【中文标题】核心数据一对多关系不存储其数据【英文标题】:Core Data One to many relation not storing its data 【发布时间】:2016-03-04 06:48:14 【问题描述】:

我有一个基于表格视图的应用程序,它有一个 MasterTableViewController 和一个 DetailChildTableViewController。

MasterTableViewController 在导航栏中有一个 +,因此用户可以看到在文本字段中输入该文件夹的名称。用户完成后,时钟完成,然后使用 Core Data 存储此文件夹,并在 MasterTableViewController 中显示此新文件夹。

这里是这个特定 TableViewController 的代码

MasterTableViewController

   class MasterTableViewController: UITableViewController, NSFetchedResultsControllerDelegate 


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

// Populate fetched results controller
func getFetchedResultController() -> NSFetchedResultsController 

    fetchedResultsController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    return fetchedResultsController




func taskFetchRequest() -> NSFetchRequest 

    let fetchRequest = NSFetchRequest(entityName: "Folder")
    let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)


    fetchRequest.sortDescriptors = [sortDescriptor]
    return fetchRequest




override viewDidLoad()
fetchedResultsController = getFetchedResultController()
    fetchedResultsController.delegate = self
    do 
        try fetchedResultsController.performFetch()
     catch _ 
    
 

 // Table View Methods to show data in Custom UITableViewCell and Segue method....

此控制器中的其余代码仅具有在表格视图单元格中显示数据的方法和一个 segue 方法,当用户点击新创建的单元格对象时,该方法将核心数据名称传递给下一个视图控制器。

这是创建此特定对象以保存并显示在 MasterTableViewController 上的代码

AddViewController

class addItemTableViewController: UITableViewController 

@IBOutlet weak var FolderName: UITextField!

// Use the same managed object to save

let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

 @IBAction func Done(sender: AnyObject)

 // Calling a function to save the folder to core data
 saveFolder()
 self.dismissViewControllerAnimated(true, completion: nil)
 

// Function that saves

func saveFolder()
 let entityDescription = NSEntityDescription.entityForName("Folder", inManagedObjectContext: managedObjectContext)
    let item = Folder(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext)

    item.name = FolderName.text!


    // Passed Value of the color picker table view below


    do 
        try managedObjectContext.save()
        print("Successfully Saved \n")
     catch _ 
    



所以这段代码基本上保存了新输入的文件夹并关闭了文件夹名称视图,MasterTableViewController 显示了这个新文件夹。

问题在于 DetailChildTableViewController,它是 MasterTableViewController 中创建的每个 Folder 的详细信息。

这是最终tableview Controller的代码

** DetailChildTableViewController**

   class DetailChildTableViewController: UITableViewController, UIPopoverPresentationControllerDelegate, NSFetchedResultsControllerDelegate 

let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

var fetchedResultsController : NSFetchedResultsController = NSFetchedResultsController()

// Populate fetched results controller
func getFetchedResultController() -> NSFetchedResultsController 

    fetchedResultsController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    return fetchedResultsController




func taskFetchRequest() -> NSFetchRequest 

    let fetchRequest = NSFetchRequest(entityName: "List")
    let sortDescriptor = NSSortDescriptor(key: "itemListName", ascending: false)


    fetchRequest.sortDescriptors = [sortDescriptor]
    return fetchRequest


 override func viewDidLoad() 
    super.viewDidLoad()

    // Core data
    fetchedResultsController = getFetchedResultController()
    fetchedResultsController.delegate = self
    do 
        try fetchedResultsController.performFetch()
     catch _ 
    

    self.tableView.reloadData()



 // MARK: - Display the results in table view

 override func numberOfSectionsInTableView(tableView: UITableView) -> Int 

    if let sections = fetchedResultsController.sections 
        return sections.count
    

    return 0


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

    if let sections = fetchedResultsController.sections 
        let currentSection = sections[section]
        return currentSection.numberOfObjects
    

    return 0



此 DetailChildTableViewController 在导航栏中也有一个 + 按钮,并会弹出一个类似的 AddViewController 以使用相同的 Core Data 方法将数据添加到此特定文件夹。

问题是当我在我的 MasterTableViewController 中创建 2 个实体时,例如:

Folder_One Folder_Two

我进入 Folder_Two 并在此文件夹中创建一个列表对象,然后返回 MasterTableViewController 然后选择 Folder_One,它仍然显示相同的列表对象我在 Folder_Two 中创建。

我该如何解决这个简单但不清楚的问题?

顺便说一下,这是我的数据模型:

TestApp.xcdatamodel

实体:

    文件夹

    列表

    属性: name 类型为 String(用于 Folder 实体) itemListName 类型为 String(用于 List 实体)

    关系:(对于文件夹实体) 关系目的地:列表

请注意,列表实体未列为与文件夹有关系。我将 Folder 设置为与 List 的关系为 一对多 关系。

我做错了什么,我该如何处理?

【问题讨论】:

【参考方案1】:

问题是您的DetailChildTableViewController 显示所有 List 对象。您需要将其限制为仅获取与当前Folder 相关的List 对象。为此,您必须具有从ListFolder 的关系。这种关系是一对一的,并且是从FolderList 的一对多关系的逆。 (你应该几乎总是为每一个关系创建一个逆。即使你觉得你不需要它,无论如何也要创建它。在这种情况下,正如你将在下面看到的,你确实需要它)。所以你的实体模型应该是这样的:

Folder          List
======          ====
name            itemListName
lists <------>> folder

在您的DetailChildTableViewController 中,添加一个新变量,该变量将是您要为其显示ListsFolder

var currentFolder : Folder?

要限制提取使其仅显示与此文件夹相关的List 对象,请在提取请求中添加谓词:

if let thisFolder = currentFolder 
    fetchRequest.predicate = NSPredicate(format:"folder == %@",thisFolder)

当用户点击MasterTableViewController 中的单元格时,在显示DetailChildTableViewController 之前,您必须为currentFolder 设置正确的值。在prepareForSegue 中,您需要以下内容:

let indexPath = self.tableView.indexPathForSelectedRow!
let currentFolder = self.fetchedResultsController.objectAtIndexPath(indexPath) as! Folder
detailViewController.currentFolder = currentFolder

同样,AddListViewController 必须有一个currentFolder 变量来知道新创建的List 应该属于哪个Folder(并且DetailChildTableViewController 中的代码必须设置为@ 987654347@)。在AddListViewController中,存储List项时,需要设置关系:

newList.folder = currentFolder

请注意,当您设置关系时,CoreData 会自动设置反向关系(假设您定义了一个)。所以newList 将被添加到currentFolderlists 属性中。

【讨论】:

我有一个问题,newList.folder 是从哪里来的?我做了所有这些,但最后一块是我不记得在我的应用程序中提到或添加的内容 另外,我对你在写“类似”的地方要说的内容有点困惑,因为我提到了不同的视图控制器,我迷失了我会跟进的地方 @harreola 我以newList 为例 - 替换您在创建新List 时使用的变量名称。所以newList.folder 是这个新创建的对象上的folder 关系。 “类似地...”段落涉及添加新的List(我猜可能是错误的,用于添加新列表的视图控制器称为AddListViewController)。当您添加一个新的List 时,您需要指定它属于哪个Folder - 因此您需要将var currentFolder : Folder? 添加到该视图控制器(并且您必须在显示该视图控制器之前设置此变量的值)。 @harreola 我根据您的代码创建了一个演示 - 请参阅 here。

以上是关于核心数据一对多关系不存储其数据的主要内容,如果未能解决你的问题,请参考以下文章

核心数据 - 将数组存储到核心数据中 一对多关系表

核心数据以一对多关系排序

核心数据:在一对多关系中匹配多个项目的组合

不搜索一对多核心数据关系

iOS 核心数据关系一对多 vs. fetchedResultsController 速度

与包含的一对多关系的核心数据谓词