NSFetchedResultsController XCode 7问题

Xcode 7 beta 6和NSFetchedResultsController今天给了我头痛。 如果我使用Xcode 6编译相同的代码(使用Swift 2修复),程序将在设备和模拟器(iOS 7,iOS8)上运行。 但是,如果我用Xcode 7 beta 6进行编译,每当我更新核心数据时,程序在设备(iOS 8.4)上崩溃,出现以下错误消息。

我得到类似于下面的错误

CoreData:错误:严重的应用程序错误。 在调用-controllerDidChangeContent:期间,NSFetchedResultsController的委托捕获到exception。 无效的更新:部分0中的行数无效。更新(2)后现有部分中包含的行数必须等于更新前(2)部分中包含的行数,加上或减去数字插入或从该部分删除的行(插入了2个,删除1个),加上或减去移入或移出该部分的行数(0移入,0移出)。 与userInfo(null)

有时它会像另一个错误崩溃

从空闲列表中出列无效指针***在malloc_error_break中设置一个断点以进行debugging

//NSFetchedResultsController delegates func controllerWillChangeContent(controller: NSFetchedResultsController) { self.tableView.beginUpdates() } func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { switch type { case .Insert: self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) case .Delete: self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) default: return } } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: print("Insert New: \(newIndexPath) Old: \(indexPath)") tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) case .Delete: print("Delete New: \(newIndexPath) Old: \(indexPath)") tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) case .Update: print("Update New: \(newIndexPath) Old: \(indexPath)") tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) //self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) case .Move: print("Move New: \(newIndexPath) Old: \(indexPath)") tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) } } func controllerDidChangeContent(controller: NSFetchedResultsController) { self.tableView.endUpdates() } 

.Update部分我也试过打电话

  self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) 

configuration单元格方法:

 func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) { let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! Person //etc } 

sorting描述符

 let sortDescriptor = NSSortDescriptor(key: "date", ascending: false) fetchRequest.sortDescriptors = [sortDescriptor] 

程序总是崩溃。 唯一的办法就是设置delagete为零,更新对象并将delagate设置回自己。

这是一个错误? 如果不是,我该如何防止呢? 谢谢

一些相同/相似问题的错误报告

https://forums.developer.apple.com/thread/12184

https://forums.developer.apple.com/thread/4999

iOS 9 – “尝试删除并重新加载相同的索引path”

我运行了XCode6和XCode7版本,并且打印了didChangeObject方法,这里是比较

XCode6 iOS 8.4

 Update New: Optional(<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) Old: Optional(<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) 

XCode 7b6 iOS 8.4

 Update New: nil Old: Optional(<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) Insert New: Optional(<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) Old: Optional(<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) 2015-09-01 01:15:37.898 TestProg[3230:200562] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-3347.44.2/UITableView.m:1623 2015-09-01 01:15:37.900 TestProg[3230:200562] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null) 

我已经尝试了几件事情,我相信这是一个错误。 正如你可以从我的日志中看到的,即使我更新现有的logging,委托获取插入消息。 在.Insert添加条件检查解决了我的问题。 我没有在表格中使用任何移动操作。 因此,如果您正在使用.Move My Current代码如下所示,也可能需要使用同样的条件操作

 func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { switch type { case .Insert: //FIXME: iOS 9 Bug! if indexPath != newIndexPath { tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) } case .Delete: tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) case .Update: tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) // self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) case .Move: tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) } } 

我试图更新单个logging,多个logging,到目前为止我还没有看到任何崩溃。 我在用

 tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) 

方法但是

 self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) 

也在我的testing过程中工作。

这在使用Xcode 7 beta 6的Sim / Device <iOS9上运行时似乎发生在我身上:

 2015-09-01 11:39:05.683 Diabetes Pal[15038:245613] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3347.44.2/UITableView.m:1623 2015-09-01 11:39:14.954 Diabetes Pal[15038:245613] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (4) must be equal to the number of rows contained in that section before the update (4), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null) Diabetes Pal(15038,0x33291d4) malloc: *** mach_vm_map(size=1048576) failed (error code=3) *** error: can't allocate region securely *** set a breakpoint in malloc_error_break to debug 

可能的解决方法是不更改animation(直到这是固定的):

 //MARK: - fetched results controller delegate func controllerWillChangeContent(controller: NSFetchedResultsController) { let ios9 = NSOperatingSystemVersion(majorVersion: 9, minorVersion: 0, patchVersion: 0) if NSProcessInfo().isOperatingSystemAtLeastVersion(ios9) { tableView?.beginUpdates() } } func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { let ios9 = NSOperatingSystemVersion(majorVersion: 9, minorVersion: 0, patchVersion: 0) if NSProcessInfo().isOperatingSystemAtLeastVersion(ios9) == false { return } //[... rest of delegate implementation ...] } func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { let ios9 = NSOperatingSystemVersion(majorVersion: 9, minorVersion: 0, patchVersion: 0) if NSProcessInfo().isOperatingSystemAtLeastVersion(ios9) == false { return }//[... rest of delegate implementation ...] } func controllerDidChangeContent(controller: NSFetchedResultsController) { let ios9 = NSOperatingSystemVersion(majorVersion: 9, minorVersion: 0, patchVersion: 0) if NSProcessInfo().isOperatingSystemAtLeastVersion(ios9) == false { tableView?.reloadData() return } tableView?.endUpdates() } 

当我使用SDK 9.1时,我没有再看到这个问题。 看来这个bug已经修复了。 你可以尝试一下。