我试图让部分在我的NSFetchResultController中工作(使用Swift 3)。这些部分的计算属性为NSManagedObject
。这些部分显示得很好。但是每当我尝试添加一个新的Object
时会生成一个新的部分,应用程序会崩溃并出现以下错误:
由于未捕获的异常终止应用程序' NSInternalInconsistencyException',原因:'无效更新:第4节中的无效行数。更新后现有部分中包含的行数(1)必须等于更新前的该部分中包含的行数(1),加上或减去从该部分插入或删除的行数(插入1个,删除0个),加上或减去移入的行数或者超出该部分(0移入,0移出)。'
我的TableViewController的FetchResultController部分如下所示:
lazy var fetchedResultsController: NSFetchedResultsController<Package> = {
let fetchRequest = NSFetchRequest<Package>(entityName:"Package")
let sectionDescriptor = NSSortDescriptor(key: "sectionTitle", ascending: true)
let sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)
fetchRequest.sortDescriptors = [sectionDescriptor , sortDescriptor]
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: "sectionTitle", cacheName: nil)
fetchedResultsController.delegate = self
return fetchedResultsController
}()
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
managedObjectContext = appDelegate.persistentContainer.viewContext
do {
try self.fetchedResultsController.performFetch()
} catch {
let fetchError = error as NSError
print("\(fetchError), \(fetchError.userInfo)")
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Package")
do {
try managedObjectContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
TableViewController的TableView数据源部分如下所示:
override func numberOfSections(in 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 1
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sections = fetchedResultsController.sections {
let currentSection = sections[section]
return currentSection.name
}
return nil
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "PackageTableCell"
let cell: PackageTableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! PackageTableViewCell
let package = fetchedResultsController.object(at: indexPath)
cell.labelId.text = String(describing: package.packageId)
cell.labelTime.text = DateFormatter.localizedString(from: package.deliveryTime as! Date, dateStyle: DateFormatter.Style.none, timeStyle: DateFormatter.Style.short)
cell.labelWeight.text = String(describing: package.weight)
cell.labelBatch.text = String(describing: package.batch!.batchId)
cell.labelRecepients.text = String(describing: package.recepients)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let package: Package = fetchedResultsController.object(at: indexPath)
managedObjectContext.delete(package)
}
}
我的TableViewController的FetchResultController委托部分如下所示:
func controllerWillChangeContent() {
tableView.beginUpdates()
}
func controllerDidChangeContent() {
tableView.endUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
tableView.insertSections(NSIndexSet(index: sectionIndex) as IndexSet, with: .fade)
case .delete:
tableView.deleteSections(NSIndexSet(index: sectionIndex) as IndexSet, with: .fade)
case .move:
break
case .update:
break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch (type) {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
let cell = tableView.cellForRow(at: indexPath!) as! PackageTableViewCell
configureCell(cell: cell, atIndexPath: indexPath! as NSIndexPath)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
}
}
然后在我的AddViewController中,我保存对象,如下所示:
@IBAction func savePressed(_ sender: UIBarButtonItem) {
if mode == .add {
let entity = NSEntityDescription.entity(forEntityName: "Package", in: self.managedObjectContext)
package = Package(entity: entity!, insertInto: self.managedObjectContext)
let packageId: Int = UserDefaults.standard.integer(forKey: "packageId")
package?.packageId = Int32(packageId)
UserDefaults.standard.set((packageId +1), forKey: "packageId")
package?.createdAt = NSDate()
package?.location = mapView.userLocation.location! as CLLocation
}
let calendar = NSCalendar.current
let selectedDate = pickerDate.date
let selectedTime = pickerTime.date
var deliveryTimeComponents = DateComponents()
deliveryTimeComponents.year = calendar.component(.year, from: selectedDate)
deliveryTimeComponents.month = calendar.component(.month, from: selectedDate)
deliveryTimeComponents.day = calendar.component(.day, from: selectedDate)
deliveryTimeComponents.hour = calendar.component(.hour, from: selectedTime)
deliveryTimeComponents.minute = calendar.component(.minute, from: selectedTime)
let deliveryTime = calendar.date(from: deliveryTimeComponents)
package?. deliveryTime = deliveryTime as NSDate?
package?.batch = batchPicker?.selectedBatch
package?.weight = Float(inputWeight.text!)!
package?.recepients = Int16(stepperRecepients.value)
package?.notes = textNotes.text!
do {
try package?.managedObjectContext?.save()
if mode == .edit {
packageTransferDelegate?. packageTransfer(transferPackage: package!)
}
dismiss(animated: true, completion: nil)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
最后我的Package Class(Package + CoreDataClass)
import Foundation
import CoreData
public class Package: NSManagedObject {
var sectionTitle: String {
return DateFormatter.localizedString(from: self.deliveryTime! as Date, dateStyle: DateFormatter.Style.long, timeStyle: DateFormatter.Style.none)
}
}
有关如何解决此问题的任何提示都将非常受欢迎。我也是iOS开发的新手,所以如果你在我的代码中看到你不喜欢的东西,请随时给我写一下
答案 0 :(得分:0)
我找到了自己问题的答案。我忘了将NSFetchResultContoller
传递给controllerWillChangeContent
和controllerDidChangeContent
函数。导致崩溃的原因。
我更正了代码如下:
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
现在一切似乎都运转得很好。