我正在制作一个简单的应用程序,用户可以在其中使用 swift 和 realm 为数据库添加习惯和完成主题
一切正常,除非我编辑状态并删除对象应用程序崩溃并出现 RLMException 原因:“索引 0 超出范围(必须小于 0)”
我注意到只有当项目是 tableView 中唯一的单元格时才会发生这种情况
如果有人能帮我解决这个问题,我将不胜感激,因为我整天都在努力解决这个问题
习惯对象是:
class Habit: Object {
dynamic var id = 0
dynamic var name = ""
dynamic var state = ""
convenience init(name: String) {
self.init()
self.id = self.incrementaID()
self.name = name
self.state = "in Progress"
}
override class func primaryKey() -> String? {
return "id"
}
private func incrementaID() -> Int {
let realm = try! Realm()
let value = realm.objects(Habit).map{$0.id}.maxElement() ?? 0
return value + 1
}}
我正在使用RealmSwift、SwiftFetchedResultsController来自动更新 tableView、swift 2 和 Xcode 7
这是MyHabitsViewController中的TableViewController相关代码
override func viewDidLoad() {
super.viewDidLoad()
// Get the default Realm
realm = try! Realm()
let predicate = NSPredicate(value: true)
let fetchRequest = FetchRequest<Habit>(realm: realm, predicate: predicate)
let sortDescriptor = SortDescriptor(property: "name", ascending: true)
let sortDescriptorSection = SortDescriptor(property: "state", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptorSection, sortDescriptor]
self.fetchedResultsController = FetchedResultsController<Habit>(fetchRequest: fetchRequest, sectionNameKeyPath: "state", cacheName: nil)
self.fetchedResultsController!.delegate = self
self.fetchedResultsController!.performFetch()
}
FetchedResultsControllerDelegate 方法:
func controllerWillChangeContent<T : Object>(controller: FetchedResultsController<T>) {
tableView.beginUpdates()
}
func controllerDidChangeSection<T : Object>(controller: FetchedResultsController<T>, section: FetchResultsSectionInfo<T>, sectionIndex: UInt, changeType: NSFetchedResultsChangeType) {
let indexSet = NSIndexSet(index: Int(sectionIndex))
switch changeType {
case .Insert:
tableView.insertSections(indexSet, withRowAnimation: .Fade)
case .Delete:
tableView.deleteSections(indexSet, withRowAnimation: .Fade)
case .Update:
tableView.reloadSections(indexSet, withRowAnimation: .Fade)
case .Move:
tableView.deleteSections(indexSet, withRowAnimation: .Fade)
tableView.insertSections(indexSet, withRowAnimation: .Fade)
}
}
func controllerDidChangeObject<T : Object>(controller: FetchedResultsController<T>, anObject: SafeObject<T>, indexPath: NSIndexPath?, changeType: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch changeType {
case .Insert:
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Delete:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Update:
tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Move:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
}
}
func controllerDidChangeContent<T : Object>(controller: FetchedResultsController<T>) {
tableView.endUpdates()
}
UITableViewDelegate & UITableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.fetchedResultsController!.numberOfSections()
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return fetchedResultsController!.titleForHeaderInSection(section)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.fetchedResultsController!.numberOfRowsForSectionIndex(section)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("HabitInfoCell", forIndexPath: indexPath) as! HabitInfoCell
let habit = self.fetchedResultsController!.objectAtIndexPath(indexPath)!
cell.configure(habit)
// add delete button
let deleteButton = MGSwipeButton() {
try! self.realm.write {
self.realm.delete(habit)
}
}
cell.leftButtons = [deleteButton]
// add complete button
let completeButton = MGSwipeButton() {
try! self.realm.write {
habit.state = "Completed"
}
}
cell.rightButtons = [completeButton]
return cell
}