NSFetchedResultsController 和多对多关系不起作用

Posted

技术标签:

【中文标题】NSFetchedResultsController 和多对多关系不起作用【英文标题】:NSFetchedResultsController and to-many relationship not working 【发布时间】:2016-09-22 04:26:29 【问题描述】:

好的,过去 1-2 周我一直在搜索和尝试这种情况,但没有成功。如果没有 NSFRC,我将能够实现我想要的,但出于性能原因和方便,我想使用 NSFRC 来实现。 所以,我有一个带有 2 个实体的 DataModel - 见图

有一个帐户,一个帐户可以有许多帐户更改-这是很明显的。 所以我希望能够选择一个帐户,然后显示该特定帐户的所有 AccountChanges。 到目前为止,我能够获取帐户并访问 cellForRow 函数中的 NSSet,但我没有得到正确的部分和 numberOfRowsInSection - 这是主要问题。

这是一些代码:

    func numberOfSections(in tableView: UITableView) -> Int 

    print("Sections : \(self.fetchedResultsController.sections?.count)")
    if (self.fetchedResultsController.sections?.count)! <= 0 
        print("There are no objects in the core data - do something else !!!")
    
    return self.fetchedResultsController.sections?.count ?? 0


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    print("Section Name")
    print(self.fetchedResultsController.sections![section].name)
    let sectionInfo = self.fetchedResultsController.sections![section]
    print("Section: \(sectionInfo) - Sections Objects: \(sectionInfo.numberOfObjects)")
    return sectionInfo.numberOfObjects

有些打印语句仅供参考!

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let myCell = myTable.dequeueReusableCell(withIdentifier: "myCell")! as UITableViewCell
    let accountBalanceChanges = self.fetchedResultsController.object(at: indexPath)
    print("AccountBalanceChanges from cell....")
    print(accountBalanceChanges)

    let details = accountBalanceChanges.accountchanges! as NSSet
    print("Print out the details:")
    print(details)
    let detailSet = details.allObjects
    let detailSetItem = detailSet.count // Just for information!


    let myPrint = detailSet[indexPath.row] as! AccountChanges
    let myVal = myPrint.category

    myCell.textLabel?.text = myVal

    return myCell

因此,我能够获取数据,但始终只能获取一个项目而不是整个集合 - 我猜是因为 section/numberOfRows 是错误的。

这是我的 NSFRC

    var fetchedResultsController: NSFetchedResultsController<Accounts> 
    if _fetchedResultsController != nil 
        return _fetchedResultsController!
    
    let fetchRequest: NSFetchRequest<Accounts> = Accounts.fetchRequest()
    // Set the batch size to a suitable number.
    fetchRequest.fetchBatchSize = 20
    // Edit the sort key as appropriate.

    let sortDescriptor = NSSortDescriptor(key: "aName", ascending: false)
    fetchRequest.sortDescriptors = [sortDescriptor]


    let predicate = NSPredicate(format: "(ANY accountchanges.accounts = %@)", newAccount!)
    fetchRequest.predicate = predicate
    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".

    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
    aFetchedResultsController.delegate = self
    _fetchedResultsController = aFetchedResultsController

    do 
        try _fetchedResultsController!.performFetch()
     catch 
        // Replace this implementation with code to handle the error appropriately.
        // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        let nserror = error as NSError
        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
    

    return _fetchedResultsController!

我假设它是 SortDescriptor 或谓词 - 或者两者兼而有之?

非常感谢任何帮助或至少指示。 我已经尝试了许多不同的方法,但没有一个能给我正确的结果。

【参考方案1】:

我会做相反的事情,我的意思是使用 FRC 获取具有特定 ID 的帐户的所有更改,并使用以下谓词:

let predicate = NSPredicate(format: "accounts.aId = %@", ACCOUNTID)

let predicate = NSPredicate(format: "accounts = %@", account.objectID)

我会将 Accounts 实体重命名为 Account 并且对于该关系来说相同,因为它是一对一的关系。 这是假设您有一个包含所有帐户的表格视图,并且当您单击一个时,它会返回其更改。

 var fetchedResultsController: NSFetchedResultsController<AccountChanges> 
    if _fetchedResultsController != nil 
        return _fetchedResultsController!
    
    let fetchRequest: NSFetchRequest<AccountChanges> = AccountChanges.fetchRequest()
    // Set the batch size to a suitable number.
    fetchRequest.fetchBatchSize = 20
    // Edit the sort key as appropriate.

    let sortDescriptor = NSSortDescriptor(key: "aName", ascending: false)
    fetchRequest.sortDescriptors = [sortDescriptor]


    let predicate = NSPredicate(format: "accounts.aId = %@", ACCOUNTID)
    fetchRequest.predicate = predicate
    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".

    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
    aFetchedResultsController.delegate = self
    _fetchedResultsController = aFetchedResultsController

    do 
        try _fetchedResultsController!.performFetch()
     catch 
        // Replace this implementation with code to handle the error appropriately.
        // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        let nserror = error as NSError
        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
    

    return _fetchedResultsController!

干杯

【讨论】:

我也想过这个问题,但是我真的不需要任何关系,因为我可以将 accountID 传递给每个帐户更改。但是因为我们可以选择使用关系,所以我想这样做。无论如何,如果没有其他解决方案,我可能会这样做并重构。我已经在我的两个数据库中都有一个唯一的 ID,我可以这样做,但是再一次,让它与关系和 NSFRC 一起工作会很好。感谢您的建议... 我的建议仍然涉及人际关系和 NSFRC。你只需要反过来取。不要获取 Accounts 并尝试从中访问更改,而是获取具有您在谓词上传递的 ID 的帐户的所有更改。 这是行不通的,它只是从帐户更改到帐户的一对一 - 无法更改,因为一个帐户更改只能影响一个帐户。从帐户到帐户更改只有一对多 - 参见图片。正如我上面写的,谓词不是问题,它是 NSFRC 中的 SortDescriptor 或 keyPath。我得到了正确的帐户,但更改的计数在sections/numberOfRows 中是错误的......如前所述,我可以在没有NSFRC 的情况下完成所有这些 - 所以问题不在于获取本身,而是使用NSFRC 进行获取,因为你从 rel 中得到一个 NSSet。 代码中的 sortDescriptor 无法正常工作,因为此键与帐户数据库相关,我已经尝试过您的方法.... 我忘记更改排序描述符。无论如何,排序描述符不是你的问题。它只是用来排序。此外,NSFRC 依赖于谓词,因此您的谓词可能是错误的。您可以轻松访问其属性 fetchedObjects 以查看是否返回了您期望从 fetch 中获得的所有结果。

以上是关于NSFetchedResultsController 和多对多关系不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 Core Data 应用程序中调用 performFetch 后,是不是需要手动更新表视图?