删除带有动画的 UITableViewCell(错误/崩溃)

Posted

技术标签:

【中文标题】删除带有动画的 UITableViewCell(错误/崩溃)【英文标题】:delete UITableViewCell with animation (error/crash) 【发布时间】:2015-03-29 15:56:29 【问题描述】:

我想用动画从UITableView 中删除一个UITableViewCell 和一个CoreData 对象。我为此编写了这段代码:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

    let mySelectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!

    //1
    let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate

    let managedContext = appDelegate.managedObjectContext!

    //2
    let fetchRequest = NSFetchRequest(entityName:"Person")

    //3
    mySelectedCell.backgroundColor = green
    mySelectedCell.detailTextLabel?.text = "Done"
    mySelectedCell.accessoryType = UITableViewCellAccessoryType.Checkmark        

    let person = people[indexPath.row]
    managedContext.deleteObject(person)
    self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Right)

我不知道为什么,但如果我选择了一个我想删除的单元格,应用程序就会崩溃。

2015-03-29 18:00:10.776 MyApp[3001:79507] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.93/UITableView.m:1582

崩溃线:self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Right)

有人知道我做错了什么吗?

更新:

tableView.beginUpdates()

var numberItems:Int = people.count

self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Right)
numberItems -= [indexPath].count // something like [indexPath].count

tableView.endUpdates()


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

    application.applicationIconBadgeNumber = people.count
    return people.count

新错误:

2015-03-29 19:14:15.972 MyApp[3389:89566] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.93/UITableView.m:1582

在这行代码中:tableView.endUpdates()

【问题讨论】:

应用程序不只是崩溃。崩溃时收到的具体错误消息是什么?它在哪条线上崩溃了? 我更新了我的问题。 您使用的是抓取结果控制器吗? 是的,我正在使用获取结果控制器。 【参考方案1】:

如果表格视图使用fetched results controller 显示Core Data 对象,那么只有你有 删除对象就是从托管对象上下文中删除对象:

let context = self.fetchedResultsController.managedObjectContext
context.deleteObject(self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject)

当然还要保存上下文以使更改永久化。

更新表格视图然后由“自动”完成 获取结果控制器委托方法

func controllerWillChangeContent(controller: NSFetchedResultsController)
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
func controllerDidChangeContent(controller: NSFetchedResultsController)

您将在 NSFetchedResultsControllerDelegate 文档,如果您还没有 已经实现了。

你也不应该在你的 people 数组。直接使用fetched results controller 在表视图数据源方法中,例如:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int 
    return self.fetchedResultsController.sections?.count ?? 0


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
    return sectionInfo.numberOfObjects


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    self.configureCell(cell, atIndexPath: indexPath)
    return cell

如果你在 Xcode 中创建一个全新的“Master-Detail + Core Data Application” 然后您将获得所需的所有必要模板代码。

【讨论】:

感谢您的回答。但我也喜欢用动画删除对象。你知道我该怎么做吗? @horst:您的意思是删除带有动画的表格视图单元格?正如我所说,如果正确实现了 NSFetchedResultsControllerDelegate 方法,那应该自动完成。例如,func controller(controller: NSFetchedResultsController, didChangeObject ...).Delete 事件的情况下调用tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)。在 Xcode 中创建一个全新的“Master-Detail + Core Data Application”,然后你会看到它是如何工作的! – 如果您需要更多信息,请告诉我。 @horst:这可能意味着 managedObjectContext 为 nil。 感谢您的帮助!现在它工作得很好。我唯一想知道的是如何通过 NSFetchedResultsController 更新 CoreData 对象。你知道我该怎么做吗? newManagedObject.setValue(date, forKey: "datum") 不工作。 @horst:要更新现有对象,您必须先获取它,然后更改属性。【参考方案2】:

你必须将你的方法 deleteRowsAtIndexPaths 放在这两个方法中,方法如下:

var path = [NSIndexPath]()

// This is only a example with the index [0..numberOfItemsToDelete-1]
for (var i = 0; i < numberOfItemsToDelete; i++) 
    path.append(NSIndexPath(forRow: i, inSection: 0))


tableView.beginUpdates()    

self.tableView.deleteRowsAtIndexPaths(path, withRowAnimation: .Right)
self.numberOfItems -= theNumberYouDeletedAbove // something like [indexPath].count

tableView.endUpdates()

当然你必须更新numberOfRowsInSection方法,因为它会抛出一个运行时错误,你可以这样做:

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

其中numberOfItems 与您用于显示项目的数组的大小相匹配。

希望对你有所帮助。

【讨论】:

我再次更新了我的问题。我发布了您说我应该使用的代码以及以下错误。 @horst [indexPath] 是什么?我认为是people[indexPath.row],而是尝试删除一对一 @horst 查看更新的答案以了解如何传递 [NSIndexPath] 数组【参考方案3】:

首先,删除试图复制和涉及 managedContext 作业导致崩溃的这一行。

self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Right)

第二,现在您应该能够在没有崩溃和动画的情况下删除。

第三,让 NSFetchedResultsController 使用“didChange”处理程序删除并触发动画。

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, 
    didChange anObject: Any, 
    at indexPath: IndexPath?, 
    for type: NSFetchedResultsChangeType, 
    newIndexPath: IndexPath?) 
    
       print(indexPath)
       if type == .delete
           tableView.deleteRows(at: [indexPath!], with: .automatic)
    


func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    tableView.endUpdates()
    //0.4 sec delay before refreshing the table
    DispatchQueue.main.asyncAfter(wallDeadline: .now() + 0.4) 
        self.refresh()
    

func refresh()
    tableView.reloadData() 

如果您无法在第二步删除; 检查,如果你已经实现:

NSFetchedResultsControllerDelegate

在类定义中并在类中设置委托,例如

yourResultsController.delegate = self

【讨论】:

以上是关于删除带有动画的 UITableViewCell(错误/崩溃)的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 删除按钮动画

在点击时全屏显示 UITableViewCell 中包含的 UIImageView 并带有动画

向左滑动时如何处理UITableViewCell删除按钮动画?

UITableViewCell 子类,在代码中绘制,动画中的删除按钮

UITableViewCell 背景色动画

UITableViewCell 上的动画按钮而不影响其他 UITableViewCell