Swift UITableView在滑动删除后冻结,但不包括整个UI

Swift UITableView在滑动删除后冻结,但不包括整个UI,swift,uitableview,core-data,nsfetchedresultscontroller,Swift,Uitableview,Core Data,Nsfetchedresultscontroller,全屏桌面视图仅适用于iPad应用程序。我已启用了对我的行进行滑动删除。行动画总是在删除后完成(CommittedItingStyle完成),但有时整个表视图会冻结。注意,不是整个UI,所以它不是一个阻塞的主线程。我可以点击列标题或点击导航控制器上的后退按钮,但表本身被锁定,无法滑动。我可以通过点击我的一个列标题按钮来解冻它 我完全不知道是什么原因导致了冰冻。我使用的是NSFetchedResultsController,下面是我的委托代码。它相当于锅炉板(更新:现在不是锅炉板。使用批处理方法)

全屏桌面视图仅适用于iPad应用程序。我已启用了对我的行进行滑动删除。行动画总是在删除后完成(CommittedItingStyle完成),但有时整个表视图会冻结。注意,不是整个UI,所以它不是一个阻塞的主线程。我可以点击列标题或点击导航控制器上的后退按钮,但表本身被锁定,无法滑动。我可以通过点击我的一个列标题按钮来解冻它

我完全不知道是什么原因导致了冰冻。我使用的是NSFetchedResultsController,下面是我的委托代码。它相当于锅炉板(更新:现在不是锅炉板。使用批处理方法):

delete在didChangeObject委托方法中被调用,但是,从技术上讲,它不是真正的delete。我只是将一个属性设置为-1,然后通过NSMangagedObjectContext保存该元素——此时,NSFRC似乎做了正确的事情,即从使用此谓词获取的获取对象列表中删除它:

NSPredicate(format: "account = %@ and quantity != -1", account)
其中,
帐户
是有效的帐户管理对象。行在90%或更多的时间内消失而没有问题。只是偶尔在动画完成后,我描述的庄园中的桌子会冻结。它永远不会冻结,删除按钮仍然显示,所以我知道它是在CommittedItingStyle被调用之后。“删除”按钮没有自定义实现。它是要删除的刷卡的默认UITableView实现。以下是我的CommittedItingStyle方法:

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        if let frameboardItem = self.fetchedResultsController.objectAtIndexPath(indexPath) as? IRMFrameBoardItemMO {
            if frameboardItem.isNew {
                // If it's never been pushed to the server, just delete locally. This will trigger a table reload
                // via NSFetchedResultsController
                DataManager.mainContext.deleteObject(frameboardItem)
            } else {
                // Otherwise mark it with a negative quantity which tells the server to delete it and tells the
                // app to hide it.
                frameboardItem.quantity = -1
            }

            do {
                try DataManager.mainContext.save()
            } catch let error as NSError {
                dLog("Something went wrong: \(error.localizedDescription)")
            }

        }

    }

}
你可以在这里看到我所说的视频。时间超过两分钟,所以你可能不想看整件事,但我会把它放在这里作为参考

我想听听你的建议

更新


我更新了NSFRC委托方法,以使用批处理方法来确保一次应用所有更新。这并没有解决这个问题。表仍会定期冻结。

使用块。

我不清楚从哪个线程访问MOC,但因为您使用的是
fetchedResultsController
,所以它可能是主线程

因此,您可能希望执行

  • deleteObject
  • 保存
执行锁定和等待中
等待。这可能有助于保证数据的完整性。大致如下:

DataManager.mainContext.performBlockAndWait{()->Void in
DataManager.mainContext.deleteObject(frameboardItem)
如果DataManager.mainContext.hasChanges{
做{
尝试DataManager.mainContext.save()
}将let错误捕获为NSError{
dLog(“出错:\(error.localizedDescription)”)
}
}
}

我认为TableView不会因为内存问题或不平衡的begin*/endEditing调用而冻结(会引发异常或发送信号)

我认为它可以在主线程之外的线程上进行操作。在这种情况下,即使是块也无济于事。(设置断点并检查哪些线程停止…,另外:在真实设备上测试)


我的想法是,尝试一些不同的方法,比如添加要添加或删除的数据到临时数组,并在一次方法运行中更新TableView(在fetch results controller结束其委托调用后,将该方法调用为在主线程上显式运行)。

我也对这个问题有所猜测。我的想法是,可以调用
controllerdChangeContent
两次或更多次,调用速度比表刷新快,这导致多次调用
tableView.beginUpdate()
,从而挂断表

所以要解决这个问题,我建议在
dispatch\u async
块中使用wrap update,或者只使用简单的布尔标志

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
         self.tableView.beginUpdates()
         // ..... rest of update code 
         self.updatedRowIndexPaths.removeAll()
    })
}
您是否尝试以更常见的方式实现NSFetchedResultsControllerDelegate的委托,我的意思是在fetchedResultController请求时开始表更新,进行更新,然后结束更新

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    self.tableView.beginUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    /* update table here */
}

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    /* update table here */
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {    
    self.tableView.endUpdates()
}
升级:
是否可能,当您“将对象标记为已删除”时,它会触发更复杂的对象更改链,从而导致多次调用didChangeObject函数?
您是否跟踪了在单个“删除标记”过程中调用didChangeObject函数的次数?

您是否确定数据源已正确更新?在以下语句中是否曾经出现过
frameboardItem
nil
的情况:
如果让frameboardItem=self.fetchedResultsController.objectAtIndexPath(indexPath)为?IRMFrameBoardItemMO
?如果它是
nil
,表是否在更新时没有更新数据源?1)表视图是否在子视图控制器中?2) 如果出于测试目的,您更改其中一个按钮(对触摸做出响应),使其触发电视滚动到顶部(或底部),它是否确实滚动?这可能会提供一条线索,说明电视是忽略触摸,还是在试图滚动时冻结。@pbasdf不完全确定我是否理解您的建议,但当“表视图”冻结时,我可以点击状态栏,并且“表视图”会按预期滚动到顶部。但是,当试图通过滑动滚动时,它仍然被冻结。@Matt谢谢-所以问题是因为电视无法接收触摸,而不是因为它无法滚动。你的电视或手机是否有任何手势识别器,可能会吞下触摸?@pbasdf Nope。手机上没有手势识别器。那么这到底在做什么呢?更新正在排队吗?@MattLong是的,更新将在队列中执行。不幸的是,这不是一个灵丹妙药,但它非常接近。我甚至用这种技术复制了冰冻现象,但频率非常低——几乎从来没有。我认为你的回答是正确的。谢谢你的邀请
func controllerWillChangeContent(controller: NSFetchedResultsController) {
    self.tableView.beginUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    /* update table here */
}

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    /* update table here */
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {    
    self.tableView.endUpdates()
}