【问题标题】:Reorder TableView using fetchedResultsController using Swift 4使用 Swift 4 使用 fetchedResultsController 重新排序 TableView
【发布时间】:2018-01-26 17:12:30
【问题描述】:

我想要做的是重新排序我的 tableview 单元格。我的 tableview 有几个部分:数据模型很简单:产品列表,每个产品都有一个类别。

我正在使用 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
  } 

当我尝试将产品放到另一个部分并出现此错误时,我的应用程序在此功能上崩溃:

由于未捕获的异常 'NSInternalInconsistencyException',原因:'无效更新:第 0 节中的行数无效。更新 (5) 后现有节中包含的行数必须等于其中包含的行数更新前的那个节 (5),加上或减去从该节插入或删除的行数(0 插入,0 删除),加上或减去移入或移出该节的行数(1 移入,0搬出去了)。'

我该如何解决这个问题?

更新

这里是完整的代码:

 @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
  } 

更新

记录数Ofrowinsection:

我只有三个部分,每个部分只有一个项目

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

我认为问题出在我显示这些部分时

事实上,当我将 nil 放入 sectionNameKeyPath: nil ==> 时,我的表格视图不再有任何部分,我也没有崩溃了但我想要表格视图中的部分

 fetchedResultsController = 
   NSFetchedResultsController(fetchRequest: Myrequest, managedObjectContext: Mycontext,
   sectionNameKeyPath: nil, cacheName: nil)

我仍在寻找答案,但我希望tableview中允许在不同部分之间拖放

【问题讨论】:

  • 您确定是let MyDestSection = objects[destinationIndexPath.row] 而不是let MyDestSection = objects[destinationIndexPath.section]?并且请遵守变量和函数名称以小写字母开头并且是camelCased而不是snake_cased的命名约定
  • @vadian :我更新代码符合命名约定。我尝试了你的建议,仍然有同样的错误。
  • objects[destinationIndexPath.row] 更改为objects[destinationIndexPath.section] 是否可以解决问题?
  • @vadian 没有同样的错误。
  • 如果您移动或删除行,您的对象模型需要与您所做的表更改一致。即来自“numberOfRowsInSection”委托的结果。我看不到您是如何将对象分成多个部分的,请查看“numberOfRowsInSection”或“cellForRowAt:”以获得您的答案。

标签: ios uitableview core-data nsfetchedresultscontroller swift4


【解决方案1】:

我不确定这是否是最干净的方法,但我通过在更新类别后重新生成 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()
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    相关资源
    最近更新 更多