当我将核心数据添加到表视图时,我的应用程序崩溃了

Posted

技术标签:

【中文标题】当我将核心数据添加到表视图时,我的应用程序崩溃了【英文标题】:My app crashes when i add core data to a table view 【发布时间】:2017-04-17 15:08:24 【问题描述】:

我在一个视图控制器中有两个表视图,它们都保存彼此不相关的不同类型的数据。出于某种原因,每当我向任一项目添加新数据时,应用程序都会崩溃,因为它将新数据添加到两个表视图中,而不仅仅是一个。我正在尝试将数据添加到正确的表格视图中。这是我的代码。

var tasks: Todo!
var progress: [Millestone] = []
var milestone: Millestone!
var list: [Todo] = []

var taskfetch: NSFetchedResultsController<Todo>!
var progressfetch : NSFetchedResultsController<Millestone>!


    let fetching: NSFetchRequest<Todo> = Todo.fetchRequest()
    let sorting = NSSortDescriptor(key: "dateadded", ascending: true)
   fetching.predicate = NSPredicate(format: "projectname = %@", "\(title! as String)")
    fetching.sortDescriptors = [sorting]
    if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) 
        let context = appDelegate.persistentContainer.viewContext
        taskfetch = NSFetchedResultsController(fetchRequest: fetching, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        taskfetch.delegate = self

        do 
            try taskfetch.performFetch()
            if let fetchedObjects = taskfetch.fetchedObjects 
                list = fetchedObjects
            
         catch 
            print(error)
        
    

    let lining: NSFetchRequest<Millestone> = Millestone.fetchRequest()
    let sorting2 = NSSortDescriptor(key: "dateadded", ascending: true)
    lining.predicate = NSPredicate(format: "projectname = %@", "\(title! as String)")
    lining.sortDescriptors = [sorting2]
    if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) 
        let context = appDelegate.persistentContainer.viewContext
        progressfetch = NSFetchedResultsController(fetchRequest: lining, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        progressfetch.delegate = self

        do 
            try progressfetch.performFetch()
            if let fetchedObjects = progressfetch.fetchedObjects 
                progress = fetchedObjects
            
         catch 
            print(error)
        
    
func getdata() 
    let context = (UIApplication.shared.delegate as! AppDelegate!).persistentContainer.viewContext

    do 
        print("getting")


        let tasking = try context.fetch(Todo.fetchRequest())


        let progressname = try context.fetch(Millestone.fetchRequest())
     catch
        print("whoopsie")
    

 let oktaskaction =  UIAlertAction(title: "Add", style: .default, handler: (action:UIAlertAction!) -> Void in

        if text.textFields?[0].text != nil, text.textFields?[0].text != "" 
           // self.taskTable.beginUpdates()
            // let song = self.songs[indexPath.row]
            //(UIApplication.shared.delegate as! AppDelegate).saveContext()
            if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
                self.tasks = Todo(context: appDelegate.persistentContainer.viewContext)
                self.tasks.taskname = text.textFields?[0].text
                self.tasks.projectname = self.title
                self.tasks.completed = false
                let formatter = DateFormatter()
                formatter.dateStyle = DateFormatter.Style.medium
                formatter.timeStyle = DateFormatter.Style.none
                self.tasks.dateadded = self.date
                appDelegate.saveContext()
            else 
                print("nothing there")
                text.textFields?[0].placeholder = "did not enter text"
            
            self.taskTable.refreshControl?.beginRefreshing()
            self.getdata()
            self.taskTable.reloadData()

        

    )


    let okAction = UIAlertAction(title: "Add Milestone", style: .default, handler: (action:UIAlertAction!) -> Void in
        if text2.textFields?[0].text != nil, text2.textFields?[0].text != "", text2.textFields?[1].text != nil 
            print("i'm working on adding the milestone")
            if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
                self.milestone = Millestone(context: appDelegate.persistentContainer.viewContext)
                self.milestone.progressname = text2.textFields?[0].text
                self.milestone.date = text2.textFields?[1].text
                self.milestone.projectname = self.title
                appDelegate.saveContext()
                    print("adding to graph")
                    self.chartLegend.append(self.milestone.progressname!)
                    self.chartData.append(self.chartData.count + 1)


                print("saved the new milestone")
            else 
                print("nothing there")
                text.textFields?[0].placeholder = "did not enter text"
            
            self.milestoneTableView.reloadData()
            self.projectlinechart.reloadData()

        

    )
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    print("Begining")
    print("\(list.count)")
    print("\(progress.count)")
    taskTable.beginUpdates()
    milestoneTableView.beginUpdates()


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

        if let newIndexPath = newIndexPath 
                print("adding")

            taskTable.insertRows(at: [newIndexPath], with: .fade)
            milestoneTableView.insertRows(at: [newIndexPath], with: .fade)

        
    case .delete:
        if let indexPath = indexPath 
            print("delete")
            taskTable.deleteRows(at: [indexPath], with: .fade)
            milestoneTableView.deleteRows(at: [indexPath], with: .fade)

        
    case .update:
        if let indexPath = indexPath 
            print("updating")
            taskTable.reloadRows(at: [indexPath], with: .fade)
            milestoneTableView.reloadRows(at: [indexPath], with: .fade)

        
    default:
        print("doing something else")
        taskTable.reloadData()
        milestoneTableView.reloadData()

    

    if let fetchedObjects = controller.fetchedObjects 
        projects = fetchedObjects as! [Project]
        list = fetchedObjects as! [Todo]
        progress = fetchedObjects as! [Millestone]
    

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
        print("ending")
        print("\(list.count)")
        print("\(progress.count)")
        taskTable.endUpdates()
        milestoneTableView.endUpdates()



    
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    if tableView.tag == 1 
        return list.count
     else if tableView.tag == 2 
        return progress.count
     else 
        return 0
    
       


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cellidentifier = "taskcell"

    let cell = tableView.dequeueReusableCell(withIdentifier: cellidentifier, for: indexPath) as! TaskTableViewCell
    if tableView.tag == 1 
        let tasks = list[indexPath.row]//this is where the crash occurs
        cell.taskname.text = tasks.taskname
        cell.taskname.adjustsFontSizeToFitWidth = true
        if tasks.completed == true 
            cell.accessoryType = .checkmark
        



   
     else if tableView.tag == 2 
        if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
            let progress2 = progress[indexPath.row]
            if (progress2.progressname != nil), progress2.date != nil
            cell.progressname.text = "\(progress2.progressname!) on \(progress2.date!)"
            cell.progressname.adjustsFontSizeToFitWidth = true
            self.chartData.append(self.chartData.count + 1)
            chartLegend.insert(cell.progressname.text!, at: indexPath.row)
             else 
                cell.progressname.text = "No Milestones"
            

        

    


    return cell

【问题讨论】:

您能分享应用程序崩溃的位置以及您收到的错误消息吗? 确保应用程序在此代码处崩溃 let tasks = list[indexPath.row] 我得到的错误是致命错误:NSArray element failed to match the Swift Array 添加异常断点并再次运行。一般来说,如果是核心数据问题,它会清楚地报告出现了什么问题并停在一线。共享控制台输出也会非常有帮助。 好的,我添加了它在 tasktable.endupdates 代码处停止的断点,我将复制并粘贴控制台输出 我也收到此错误,但它不会使应用程序崩溃 在调用 -controllerDidChangeContent: 期间,从 NSFetchedResultsController 的委托中捕获了异常。无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (2) 必须等于更新前该节中包含的行数 (5),加上或减去数字从该部分插入或删除的行数(1 插入,0 删除)加上或减去移入或移出该部分的行数(0 移入,0 移出)。与 userInfo (null) 【参考方案1】:

去掉下面的变量progresslist。 fetchedResultsController 正在跟踪对象的更改,因此当对象被删除、插入或移动时,它会为您更新。通过将获取的结果复制到数组中,您可以在发生更改后查看过时的信息。而是直接查看 fetchedResultsController 的值(即访问self.taskfetch.fetchedObjects 或使用self.taskfetch.object(at:indexPath)

导致崩溃的原因是因为您正在根据 fetchedResultsController(s) 通知您的更改更新您的 tableview,但由于您查看的是旧的陈旧数据而没有更新表中的行数。

另一个问题是,当任一组数据更改时,您都在更新两个表。因此,如果在一组数据中插入了某些内容,则会在错误的表中错误地插入一行。在所有控制器方法中,首先检查它是哪个控制器。类似if controller == taskfetch

【讨论】:

是否有可能我需要为每组数据创建两个不同的变化函数?

以上是关于当我将核心数据添加到表视图时,我的应用程序崩溃了的主要内容,如果未能解决你的问题,请参考以下文章

当我关闭视图时Coredata崩溃

当我删除核心数据实体的最后一条记录时,为啥我的应用程序崩溃了?

核心数据:移动到详细视图时获取崩溃

当我将 ImageView 添加到 CardView 或 Fragment 时,为啥我的应用程序会崩溃?

核心数据 - 向 xcddatamodel 文件添加额外属性后应用程序崩溃

当我将滚动方向从垂直更改为水平时,为啥集合视图会崩溃?