使用 Swift 4 使用 fetchedResultsController 对 TableView 重新排序
Reorder TableView using fetchedResultsController using Swift 4
我想做的是重新排序我的 tableview 单元格。我的 table 视图有以下部分:数据模型 简单的:产品列表,每个产品都有一个类别。
我正在使用 UITableViewDropDelegate、UITableViewDragDelegate,因为我不喜欢 tableview 中的编辑模式(红色按钮让我抓狂):
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
var objects = self.fetchedResultsController.fetchedObjects! as [TblProduits]
self.fetchedResultsController.delegate = nil
//get the destination section
let myDestSection = objects[destinationIndexPath.row]
let object = objects[sourceIndexPath.row]
objects.remove(at: sourceIndexPath.row)
//updating product categorie with the destination categorie before inserting
object.categorie = myDestSection.categorie
objects.insert(object, at: destinationIndexPath.row)
fctSaveListDesProduits()
self.fetchedResultsController.delegate = self
}
当我尝试将产品放入另一个部分并出现此错误时,我的应用程序在此功能上崩溃:
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 (5) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (1 moved in, 0 moved out).'
我该如何解决这个问题?
已更新
完整代码如下:
@IBOutlet var TblView_Produit: UITableView!
let Mycontext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let Myrequest : NSFetchRequest<TblProduits> = TblProduits.fetchRequest()
var fetchedResultsController : NSFetchedResultsController<TblProduits>!
var managedObjectContext: NSManagedObjectContext? = nil
override func viewDidLoad() {
super.viewDidLoad()
TblView_Produit.dragDelegate = self
TblView_Produit.dropDelegate = self
TblView_Produit.dragInteractionEnabled = true
// Load Data
Fct_loadListDesProduits()
fetchedResultsController.delegate = self
}
func Fct_SaveListDesProduits() {
do {
try Mycontext.save()
// print ("saved ligne \(i)")
} catch {
debugPrint ("there is an error \(error.localizedDescription)")
}
}
func Fct_loadListDesProduits () {
let MySortDescriptor = NSSortDescriptor(key: #keyPath(TblProduits.categorie.categorie_Name), ascending: true)
Myrequest.sortDescriptors = [MySortDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: Myrequest, managedObjectContext: Mycontext, sectionNameKeyPath: #keyPath(TblProduits.categorie.categorie_Name), cacheName: nil)
do {
try fetchedResultsController.performFetch()
} catch {
debugPrint ("there is an error \(error.localizedDescription)")
}
}
func numberOfSections(in tableView: UITableView) -> Int {
guard let sections = self.fetchedResultsController.sections else {
return 0
}
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = self.fetchedResultsController.sections else {
return 0
}
return sections[section].numberOfObjects
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let sections = self.fetchedResultsController.sections else {
return ""
}
return sections[section].name
}
// MARK: - FetchedResultsController Delegate
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch(type) {
case .insert:
if let Myindexpath = newIndexPath {
self.TblView_Produit.insertRows(at: [Myindexpath], with: .left)
}
break;
case .delete:
if let MyindexPath = indexPath {
TblView_Produit.deleteRows(at: [MyindexPath], with: .fade)
}
break;
case .move:
break;
case .update:
break;
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
TblView_Produit.endUpdates()
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
TblView_Produit.beginUpdates()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! ProduitTableViewCell
if let ProduitName = self.fetchedResultsController.object(at: indexPath).produit_name { //ProductTable[indexPath.row].produit_name{
cell.SetListeDesProduits(ProduitName: ProduitName)
}
// cell.isEditing = self.tableView(tableView, canMoveRowAt: indexPath)
return cell
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
var objects = self.fetchedResultsController.fetchedObjects! as [TblProduits]
self.fetchedResultsController.delegate = nil
//get the destination section
let myDestSection = objects[destinationIndexPath.section]
let object = objects[sourceIndexPath.row]
objects.remove(at: sourceIndexPath.row)
//updating product categorie with the destination categorie before inserting
object.categorie = myDestSection.categorie
objects.insert(object, at: destinationIndexPath.row)
fctSaveListDesProduits()
self.fetchedResultsController.delegate = self
}
更新
记录段数:
我只有三个部分,每个部分只有一个项目
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
当我将项目从第二部分拖放到第一部分时
section
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
018-01-26 19:56:05.492956+0100 ShopTogether[8815:1168659] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/UITableView.m:2011
2018-01-26 19:56:05.513608+0100 ShopTogether[8815:1168659] *** 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 (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (1 moved in, 0 moved out).'
// 更新 Fetchcontroller
我认为问题出在我显示部分时
事实上,当我在 sectionNameKeyPath 中放入 nil 时:nil ==> 我的 table 视图不再有部分,我也没有崩溃 但我想要我的部分 table 查看.
fetchedResultsController =
NSFetchedResultsController(fetchRequest: Myrequest, managedObjectContext: Mycontext,
sectionNameKeyPath: nil, cacheName: nil)
我仍在寻找答案,但我希望在 tableview.
中允许在不同 部分之间拖放
我不确定这是否是最干净的方法但我通过重新生成 TableView 并在更新类别后插入对象解决了我的问题。
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
self.fetchedResultsController.delegate = nil
var objects = self.fetchedResultsController.fetchedObjects
let objectSource = fetchedResultsController.object(at: IndexPath(row: sourceIndexPath.row, section: sourceIndexPath.section))
let MyCategorie = fetchedResultsController.object(at: IndexPath(row: 0, section: destinationIndexPath.section)).categorie
objectSource.categorie = MyCategorie
objects?.remove(at: sourceIndexPath.row)
objects?.insert(objectSource, at: destinationIndexPath.row)
Fct_SaveListDesProduits()
self.fetchedResultsController.delegate = self
// REGENRATING TABLEVIEW
Fct_loadListDesProduits()
}
我想做的是重新排序我的 tableview 单元格。我的 table 视图有以下部分:数据模型 简单的:产品列表,每个产品都有一个类别。
我正在使用 UITableViewDropDelegate、UITableViewDragDelegate,因为我不喜欢 tableview 中的编辑模式(红色按钮让我抓狂):
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
var objects = self.fetchedResultsController.fetchedObjects! as [TblProduits]
self.fetchedResultsController.delegate = nil
//get the destination section
let myDestSection = objects[destinationIndexPath.row]
let object = objects[sourceIndexPath.row]
objects.remove(at: sourceIndexPath.row)
//updating product categorie with the destination categorie before inserting
object.categorie = myDestSection.categorie
objects.insert(object, at: destinationIndexPath.row)
fctSaveListDesProduits()
self.fetchedResultsController.delegate = self
}
当我尝试将产品放入另一个部分并出现此错误时,我的应用程序在此功能上崩溃:
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 (5) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (1 moved in, 0 moved out).'
我该如何解决这个问题?
已更新
完整代码如下:
@IBOutlet var TblView_Produit: UITableView!
let Mycontext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let Myrequest : NSFetchRequest<TblProduits> = TblProduits.fetchRequest()
var fetchedResultsController : NSFetchedResultsController<TblProduits>!
var managedObjectContext: NSManagedObjectContext? = nil
override func viewDidLoad() {
super.viewDidLoad()
TblView_Produit.dragDelegate = self
TblView_Produit.dropDelegate = self
TblView_Produit.dragInteractionEnabled = true
// Load Data
Fct_loadListDesProduits()
fetchedResultsController.delegate = self
}
func Fct_SaveListDesProduits() {
do {
try Mycontext.save()
// print ("saved ligne \(i)")
} catch {
debugPrint ("there is an error \(error.localizedDescription)")
}
}
func Fct_loadListDesProduits () {
let MySortDescriptor = NSSortDescriptor(key: #keyPath(TblProduits.categorie.categorie_Name), ascending: true)
Myrequest.sortDescriptors = [MySortDescriptor]
fetchedResultsController = NSFetchedResultsController(fetchRequest: Myrequest, managedObjectContext: Mycontext, sectionNameKeyPath: #keyPath(TblProduits.categorie.categorie_Name), cacheName: nil)
do {
try fetchedResultsController.performFetch()
} catch {
debugPrint ("there is an error \(error.localizedDescription)")
}
}
func numberOfSections(in tableView: UITableView) -> Int {
guard let sections = self.fetchedResultsController.sections else {
return 0
}
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = self.fetchedResultsController.sections else {
return 0
}
return sections[section].numberOfObjects
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let sections = self.fetchedResultsController.sections else {
return ""
}
return sections[section].name
}
// MARK: - FetchedResultsController Delegate
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch(type) {
case .insert:
if let Myindexpath = newIndexPath {
self.TblView_Produit.insertRows(at: [Myindexpath], with: .left)
}
break;
case .delete:
if let MyindexPath = indexPath {
TblView_Produit.deleteRows(at: [MyindexPath], with: .fade)
}
break;
case .move:
break;
case .update:
break;
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
TblView_Produit.endUpdates()
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
TblView_Produit.beginUpdates()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! ProduitTableViewCell
if let ProduitName = self.fetchedResultsController.object(at: indexPath).produit_name { //ProductTable[indexPath.row].produit_name{
cell.SetListeDesProduits(ProduitName: ProduitName)
}
// cell.isEditing = self.tableView(tableView, canMoveRowAt: indexPath)
return cell
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
var objects = self.fetchedResultsController.fetchedObjects! as [TblProduits]
self.fetchedResultsController.delegate = nil
//get the destination section
let myDestSection = objects[destinationIndexPath.section]
let object = objects[sourceIndexPath.row]
objects.remove(at: sourceIndexPath.row)
//updating product categorie with the destination categorie before inserting
object.categorie = myDestSection.categorie
objects.insert(object, at: destinationIndexPath.row)
fctSaveListDesProduits()
self.fetchedResultsController.delegate = self
}
更新
记录段数:
我只有三个部分,每个部分只有一个项目
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
当我将项目从第二部分拖放到第一部分时
section
section : 0
sections[section].numberOfObjects: 1
section : 1
sections[section].numberOfObjects: 1
section : 2
sections[section].numberOfObjects: 1
018-01-26 19:56:05.492956+0100 ShopTogether[8815:1168659] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/UITableView.m:2011
2018-01-26 19:56:05.513608+0100 ShopTogether[8815:1168659] *** 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 (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (1 moved in, 0 moved out).'
// 更新 Fetchcontroller
我认为问题出在我显示部分时
事实上,当我在 sectionNameKeyPath 中放入 nil 时:nil ==> 我的 table 视图不再有部分,我也没有崩溃 但我想要我的部分 table 查看.
fetchedResultsController =
NSFetchedResultsController(fetchRequest: Myrequest, managedObjectContext: Mycontext,
sectionNameKeyPath: nil, cacheName: nil)
我仍在寻找答案,但我希望在 tableview.
中允许在不同 部分之间拖放我不确定这是否是最干净的方法但我通过重新生成 TableView 并在更新类别后插入对象解决了我的问题。
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
self.fetchedResultsController.delegate = nil
var objects = self.fetchedResultsController.fetchedObjects
let objectSource = fetchedResultsController.object(at: IndexPath(row: sourceIndexPath.row, section: sourceIndexPath.section))
let MyCategorie = fetchedResultsController.object(at: IndexPath(row: 0, section: destinationIndexPath.section)).categorie
objectSource.categorie = MyCategorie
objects?.remove(at: sourceIndexPath.row)
objects?.insert(objectSource, at: destinationIndexPath.row)
Fct_SaveListDesProduits()
self.fetchedResultsController.delegate = self
// REGENRATING TABLEVIEW
Fct_loadListDesProduits()
}