Swift UITableView删除行项目 - tableview数据源是核心数据
我几乎完成了我的第一个iOS应用程序,但有一个问题从正在从核心数据填充的表视图中删除。核心数据实体具有4个显示在单元中的属性。我试图遵循的所有示例都使用一个归因实体。另外我有两种类型的描述。不知道这是否对我的问题有任何影响。我的tableview正确填入..编辑选项可用,但一旦行被选中并删除感动我得到一个错误,调试器停止在该行class AppDelegate: UIResponder, UIApplicationDelegate {
和Xcode的输出以下Swift UITableView删除行项目 - tableview数据源是核心数据
2016-04-25 20:00:05.739 MileageLogger[41673:17841244] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UITableView.m:1716
2016-04-25 20:00:05.768 MileageLogger[41673:17841244] *** 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 (14) must be equal to the number of rows contained in that section before the update (14), 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).'
*** First throw call stack:
(
0 CoreFoundation 0x00633494 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x02347e02 objc_exception_throw + 50
2 CoreFoundation 0x0063332a +[NSException raise:format:arguments:] + 138
3 Foundation 0x00a78322 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118
4 UIKit 0x00f7b014 -[UITableView _endCellAnimationsWithContext:] + 17170
5 UIKit 0x00f94216 -[UITableView _updateRowsAtIndexPaths:updateAction:withRowAnimation:] + 363
6 UIKit 0x00f942a4 -[UITableView deleteRowsAtIndexPaths:withRowAnimation:] + 56
7 UIKit 0x0fec584a -[UITableViewAccessibility deleteRowsAtIndexPaths:withRowAnimation:] + 65
8 MileageLogger 0x00062789 _TFC13MileageLogger30MileageLogsTableViewController9tableViewfTCSo11UITableView18commitEditingStyleOSC27UITableViewCellEditingStyle17forRowAtIndexPathCSo11NSIndexPath_T_ + 201
9 MileageLogger 0x00062827 _TToFC13MileageLogger30MileageLogsTableViewController9tableViewfTCSo11UITableView18commitEditingStyleOSC27UITableViewCellEditingStyle17forRowAtIndexPathCSo11NSIndexPath_T_ + 103
10 UIKit 0x00fafc94 -[UITableView animateDeletionOfRowWithCell:] + 185
11 UIKit 0x00f80ce5 __52-[UITableView _swipeActionButtonsForRowAtIndexPath:]_block_invoke + 110
12 UIKit 0x00fb17f3 -[UITableView _actionButton:pushedInCell:] + 178
13 UIKit 0x0121cc68 -[UITableViewCell _actionButtonPushed:] + 88
14 libobjc.A.dylib 0x0235c0b5 -[NSObject performSelector:withObject:withObject:] + 84
15 UIKit 0x00e23e38 -[UIApplication sendAction:to:from:forEvent:] + 118
16 UIKit 0x00e23db7 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
17 UIKit 0x00fc7f3b -[UIControl sendAction:to:forEvent:] + 79
18 UIKit 0x00fc82d4 -[UIControl _sendActionsForEvents:withEvent:] + 433
19 UIKit 0x00fc72c1 -[UIControl touchesEnded:withEvent:] + 714
20 UIKit 0x013aad2e _UIGestureRecognizerUpdate + 12763
21 UIKit 0x00ea3efd -[UIWindow _sendGesturesForEvent:] + 1559
22 UIKit 0x00ea55b6 -[UIWindow sendEvent:] + 1137
23 UIKit 0x00e46be8 -[UIApplication sendEvent:] + 266
24 UIKit 0x0febc369 -[UIApplicationAccessibility sendEvent:] + 72
25 UIKit 0x00e1b769 _UIApplicationHandleEventQueue + 7795
26 CoreFoundation 0x00545e5f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
27 CoreFoundation 0x0053baeb __CFRunLoopDoSources0 + 523
28 CoreFoundation 0x0053af08 __CFRunLoopRun + 1032
29 CoreFoundation 0x0053a846 CFRunLoopRunSpecific + 470
30 CoreFoundation 0x0053a65b CFRunLoopRunInMode + 123
31 GraphicsServices 0x04b2f664 GSEventRunModal + 192
32 GraphicsServices 0x04b2f4a1 GSEventRun + 104
33 UIKit 0x00e21eb9 UIApplicationMain + 160
34 MileageLogger 0x00055201 main + 145
35 libdyld.dylib 0x02d67a25 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
我的代码是TableViewController是...
import UIKit
import CoreData
class MileageLogsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
@IBOutlet var milageLogTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
do {
try fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("Unable to fetch MileageLog")
print("\(fetchError), \(fetchError.localizedDescription)")
}
// Display an Edit button in the navigation bar for this view controller.
self.navigationItem.leftBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
private lazy var fetchedResultsController: NSFetchedResultsController = {
// Initialize Fetch Request
let fetchRequest = NSFetchRequest(entityName: "MileageLog")
// Add Sort Descriptors
let dateSort = NSSortDescriptor(key: "tripDate", ascending: false)
let mileSort = NSSortDescriptor(key: "startMileage", ascending: false)
fetchRequest.sortDescriptors = [dateSort, mileSort]
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedObjectContext = delegate.managedObjectContext
// Initialize Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: "rootCache")
return fetchedResultsController
}()
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if let sections = fetchedResultsController.sections {
return sections.count
}
return 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let sections = fetchedResultsController.sections {
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MileageLogCell") as! MileageTableViewCell
// Fetch MileageLog
if let mileageLog = fetchedResultsController.objectAtIndexPath(indexPath) as? MileageLog {
//format date as medium style date
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
let logDateString = formatter.stringFromDate(mileageLog.tripDate!)
//format NSNumber mileage to string
let mileageInt:NSNumber = mileageLog.startMileage!
let mileageString = String(mileageInt)
cell.lb_LogDate.text = logDateString
cell.lb_LogMileage.text = mileageString
cell.lb_LogStartLocation.text = mileageLog.startLocation
cell.lb_LogDestination.text = mileageLog.endLocation
}
return cell
}
// Override to support conditional editing of the table view.
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 to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
// Delete the row from the data source
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default :
return
}
}
}
我正在努力寻找解决方案...任何帮助表示赞赏。
deleteRowsAtIndexPaths
只更新视图,而不是模型,你也必须删除对象的核心数据
...
case .Delete:
// Delete the row from the data source
let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
let context = fetchedResultsController.managedObjectContext
context.deleteObject(objectToDelete)
do {
try context.save()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} catch {
print(error)
}
当使用NSFetchedResultsController
它强烈建议实现委托方法来处理用户界面的更新那里。
瓦迪亚,感谢作出改变,建议删除。我仍然收到类似的错误。由于未捕获异常'NSInternalInconsistencyException'而终止应用程序,原因如下:'无效更新:第0节中的行数无效。更新(13)后现有节中包含的行数必须等于该节中包含的行数更新前的部分(13),加上或减去从该部分插入或删除的行数(0插入,1删除),加上或减去移入或移出该部分的行数(0移入,0移入出)。” – Mych
注意我现在只有13行...之前我有14个。所以它看起来像核心数据被删除,但tableview无法更新。 – Mych
现在您需要实现'NSFetchedResultsControllerDelegate'方法,以便您可以通知操作的表视图。 –
你可以写FUNC controllerWillChangeContent(控制器:NSFetchedResultsController){ tableView.beginUpdates() } FUNC controllerDidChangeContent(控制器:NSFetchedResultsController){ tableView.endUpdates() } –
我认为你必须编辑的数据源首先与您的新显示行保持一致。也许把数据放到一个数组中,在调用deleteRows之前删除相关的索引。不幸的是,当它在一个fetchedResultsController中时,我不知道如何改变dataSource。不幸的是, –
@Mych:最简单,但一个小小的代价就是调用self。 tableView.reloadData()在删除的情况下:) –