Swift 3 Core Data - 获取结果控制器

Posted

技术标签:

【中文标题】Swift 3 Core Data - 获取结果控制器【英文标题】:Swift3 CoreData - fetchResultsController 【发布时间】:2017-06-25 17:42:27 【问题描述】:

我收到此错误: ItinerariesCodeChallenge[2594:1022206] *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“NSFetchedResultsController 的一个实例需要一个带有排序描述符的获取请求这是我的代码。非常感谢您的帮助,我已经尝试了好几天了...

import UIKit
import CoreData

class MainVC: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate 


    // outlets & properties:

    @IBOutlet weak var tableView: UITableView!

   var controller: NSFetchedResultsController<Itineraries>!


    override func viewDidLoad() 
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self


    

    override func viewWillAppear(_ animated: Bool) 
        attemptFetch()
        tableView.reloadData()

    



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

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CellContent

        configureCell(cell: cell, indexPath: indexPath as NSIndexPath)

        return cell


    

    func configureCell(cell: CellContent, indexPath: NSIndexPath) 
        let itinerary = controller.object(at: indexPath as IndexPath)
        cell.configureCell(itineraries: itinerary)

    

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        if let objs = controller.fetchedObjects, objs.count > 0 
            let itinerary = objs[indexPath.row]
            performSegue(withIdentifier: "toDetailsVC", sender: itinerary)
        
    



    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

        if segue.identifier == "toDetailsVC" 
            if let destination = segue.destination as? DetailVC 
                if let itinerary = sender as? Itineraries 
                    destination.itineraryToEdit = itinerary
                
            
        
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        if let sections = controller.sections 

            let sectionInfo = sections[section]
            return sectionInfo.numberOfObjects

        
        return 0
    

    func numberOfSections(in tableView: UITableView) -> Int 

        if let sections = controller.sections 
            return sections.count
        
        return 0
    

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 140
    

    func attemptFetch() 

        let fetchRequest: NSFetchRequest<Itineraries> = Itineraries.fetchRequest()

        let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)

        controller.delegate = self

        self.controller = controller

        do 

            try controller.performFetch()

         catch 

            let error = error as NSError
            print("\(error)")
        


    


    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
        tableView.beginUpdates()
    

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
        tableView.endUpdates()
    

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 

        switch(type) 

        case.insert:
            if let indexPath = newIndexPath 
                tableView.insertRows(at: [indexPath], with: .fade)
            
            break

        case.delete:
            if let indexPath = indexPath 
                tableView.deleteRows(at: [indexPath], with: .fade)
            
            break

        case.update:
            if let indexPath = indexPath 
                let cell = tableView.cellForRow(at: indexPath) as! CellContent
                configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
            
            break

        case.move:
            if let indexPath = indexPath 
                tableView.deleteRows(at: [indexPath], with: .fade)
            
            if let indexPath = newIndexPath 
                tableView.insertRows(at: [indexPath], with: .fade)
            
            break

        

【问题讨论】:

【参考方案1】:

请仔细阅读错误信息,它准确地说明了问题所在

NSFetchedResultsController 的实例需要带有排序描述符的获取请求。

添加至少一个排序描述符:

let fetchRequest: NSFetchRequest<Itineraries> = Itineraries.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "...")] 
let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)

旁注,与问题无关:删除所有类型转换as NSIndexPath,它们是多余的。

【讨论】:

以上是关于Swift 3 Core Data - 获取结果控制器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用swift 3仅获取Core Data中的一列数据

何时在 Swift 中使用 Core Data 关系?

Swift 3 Core Data - 无法保存关系值

如何使用 Swift 在 Core Data 中组合属性?

Swift Core Data NSFetchRequest 没有结果

在 Swift Core Data 中对存储的数据模型提取进行排序