简体   繁体   English

删除导致应用崩溃

[英]Deleting causes app to crash

I am trying to put together my first iOS app (I'm primarily a PHP dev), and I am running into an issue. 我正在尝试整理我的第一个iOS应用程序(主要是PHP开发人员),但遇到了问题。 I was trying to follow a tutorial to make a simple task manager app, and I have everything working except the delete functionality. 我试图按照一个教程制作一个简单的任务管理器应用程序,除了删除功能之外,我都能正常工作。

As soon as I try to delete an item, the app crashes with the following error: 一旦我尝试删除项目,应用程序就会崩溃并显示以下错误:

2015-06-10 08:33:32.532 Tasks[56594:1355112] *** Assertion failure in
-[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3347.44/UITableView.m:1623

2015-06-10 08:33:32.538 Tasks[56594:1355112] *** Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in
section 0.  The number of rows contained in an existing section after the update (1) must
be equal to the number of rows contained in that section before the update (1), plus or
minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and
plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

There's a throw call stack message afterwards that I can post too, if need be. 之后有一个throw call stack消息,如果需要的话,我也可以发布。

Here's my MasterViewController.swift document: 这是我的MasterViewController.swift文件:

//
//  MasterViewController.swift
//  Tasks
//
//  Created by John Doe on 6/9/15.
//  Copyright (c) 2015 John Doe. All rights reserved.
//

import UIKit

class MasterViewController: UITableViewController {

    var objects = [Task]()

    var count: Int {
        return objects.count
    }

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.navigationItem.leftBarButtonItem = self.editButtonItem()
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated);
        self.objects = TaskStore.sharedInstance.tasks;
        self.tableView.reloadData();
    }

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

    // MARK: - Segues

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showDetail" {
            if let indexPath = self.tableView.indexPathForSelectedRow() {
                let task = TaskStore.sharedInstance.get(indexPath.row)
                (segue.destinationViewController as! DetailViewController).detailItem = task
            }
        }
    }

    // MARK: - Table View

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

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return objects.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell

        let task = TaskStore.sharedInstance.get(indexPath.row)
        cell.textLabel?.text = task.title
        cell.detailTextLabel?.text = task.notes
        return cell
    }

    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }

    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            TaskStore.sharedInstance.removeTaskAtIndex(indexPath.row)
            tableView.beginUpdates()
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
            tableView.endUpdates()
        } else if editingStyle == .Insert {
            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
        }
    }


}

A friend mentioned that I should add the beginUpdates() and endUpdates() methods before and after my code that deletes, but I still get the same error message and crash. 一位朋友提到我应该在删除的代码之前和之后添加beginUpdates()和endUpdates()方法,但是我仍然会收到相同的错误消息并崩溃。

Any advice would be most appreciated, I feel like reading through the reference isn't getting me anywhere. 任何建议将不胜感激,我觉得通读参考资料无济于事。 Thanks! 谢谢!

It has nothing to do with beginUpdates() and endUpdates() ; 它与beginUpdates()endUpdates() those are used if you need multiple animations (insert x rows in section 1, remove y rows in section 2) at once. 如果您需要多个动画(在第1节中插入x行,在第2节中删除y行),则一次使用这些动画。

Your problem lies in the fact that you're sometimes using the local variable objects and sometimes the TaskStore.sharedInstance . 您的问题在于您有时使用局部变量objects ,有时甚至使用TaskStore.sharedInstance You are deleting the task from the TaskStore, but you are still using the objects to determine the amount of rows. 您正在从TaskStore中删除任务,但仍在使用objects来确定行数。

The easiest way is to get rid of objects entirely, and only use the TaskStore.sharedInstance . 最简单的方法是完全摆脱objects ,而仅使用TaskStore.sharedInstance However, there are certain cases where it makes sense to retain a local copy, eg if you include 'Save' and 'Cancel' buttons. 但是,在某些情况下,保留本地副本是有意义的,例如,如果包含“保存”和“取消”按钮。 In that case, you should fetch the objects in viewDidLoad (as you do now), use objects everywhere else, and when the user clicks 'Save', write the changes back to the store. 在这种情况下,您应该像现在一样在viewDidLoad获取对象,在其他地方使用objects ,并且当用户单击“保存”时,将更改写回到存储中。

After deleting synchronise your objects array. 删除后,同步objects数组。

self.objects = TaskStore.sharedInstance.tasks

If you want to use objects array as a source of data, use it everywhere. 如果要将objects数组用作数据源,请在各处使用它。 Or don't use it at all and use TaskStore.sharedInstance instead. 或者根本不使用它,而改用TaskStore.sharedInstance

I'm guessing that TaskStore.sharedInstance.tasks is not a mutable array. 我猜测TaskStore.sharedInstance.tasks不是可变数组。 When you assign objects to TaskStore.sharedInstance.tasks , then modify the non-mutable array, you're basically creating a new array and discarding the old one (only it's not discarded because objects keeps a reference to it), then assigning the new array to TaskStore.sharedInstance.tasks . 当您将对象分配给TaskStore.sharedInstance.tasks ,然后修改非可变数组时,您基本上是在创建一个新数组并丢弃旧数组(只是不丢弃它,因为objects保留了对它的引用),然后分配新数组数组到TaskStore.sharedInstance.tasks Now, TaskStore.sharedInstance.tasks is different than the array that objects point to. 现在, TaskStore.sharedInstance.tasksobjects指向的数组不同。

Since the count of the table rows and objects.count differs, you get the error. 由于表行和objects.count的计数不同,因此会出现错误。

You should consider using a mutable array, update objects after you modify the array, or stop using the variable objects . 您应该考虑使用可变数组,在修改数组后更新objects ,或者停止使用变量objects

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM