错误消息:-[UITableView_Bug_Detected_In_Client_Of_UITableView_Invalid_Number_Of_Sections:] 中断言失败,UITableView.m:2615

问题描述 投票:0回答:1

大家好!

使用 Xcode 14.3 和 Swift 5

在视图控制器上,我想显示一个由部分分隔的表格视图,其中包含我在同一视图上输入的信息。

故事板有 3 个文本字段(用于片段描述、ID 和图像)、一个选择器视图(用户可以在其中选择存储位置)和表格视图。

选择器视图是通过另一个查看器填充的,并且似乎工作正常。

按下“保存”按钮时,将读取并保存 3 个字段和选择器视图,表格应将位置显示为部分标题以及带有部分的所有部分。

Core Data中有2个实体,PieceEntity和StorageEntity。第一个具有属性pieceDescription、pieceID 和pieceImageNo 以及与StorageEntity 的关系存储,具有逆件和类型To One。 StorageEntity 只有一个属性,位置和 PieceEntity 的关系。

表格视图中的项目是可删除的。

class AddPieceViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
  var fetchedResultsController: NSFetchedResultsController<PieceEntity>!

  override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
            fatalError("AppDelegate not found.")
        }
        managedObjectContext = appDelegate.persistentContainer.viewContext
        
        // Set up the fetched results controller
        let fetchRequest: NSFetchRequest<PieceEntity> = PieceEntity.fetchRequest()
        let sortDescriptor = NSSortDescriptor(key: "pieceID", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]

        /*fetchedResultsController = NSFetchedResultsController(
            fetchRequest: fetchRequest,
            managedObjectContext: managedObjectContext, // Your managed object context
            sectionNameKeyPath: nil,
            cacheName: nil
        )*/
        
        //actually, sectionNameKeyPath: "bin.location" gives the assertion failure
        fetchedResultsController = NSFetchedResultsController(
            fetchRequest: fetchRequest,
            managedObjectContext: managedObjectContext, // Your managed object context
            sectionNameKeyPath: "storage.location",
            cacheName: nil
        )

        fetchedResultsController.delegate = self // NSFetchedResultsControllerDelegate
        
        // Perform the initial fetch
        do {
            try fetchedResultsController.performFetch()
        } catch {
            print("Error fetching data: \(error)")
        }
        
        // Populate the storageLocations array from Core Data
        …
        storageLocationPickerView.reloadAllComponents()
    }

  override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // Initialize Core Data stack
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
            fatalError("AppDelegate not found.")
        }
        managedObjectContext = appDelegate.persistentContainer.viewContext
    }

保存功能及扩展:

    @IBAction func save(sender: UIBarButtonItem) {
        print("save")
        guard
            let pieceDescription = addPieceDescriptionTextField.text,
            let pieceIDText = addPieceIDTextField.text,
            let pieceID = Double(pieceIDText),
            let pieceImageNo = addPieceImageNoTextField.text
        else {
            print("return without save")
            return }
        
        // Access the selected storage location
        let selectedRow = storageLocationPickerView.selectedRow(inComponent: 0)
        let selectedStorageLocation = storageLocations[selectedRow]
        
        // Fetch the existing StorageEntity with the selected location
        /*let fetchRequest: NSFetchRequest<StorageEntity> = StorageEntity.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "location == %@", selectedStorage)
        */
        print("selectedStorage before newPiece: \(selectedStorageLocation)")
        
        let newPiece = PieceEntity(context: managedObjectContext)
        newPiece.pieceDescription = pieceDescription
        newPiece.pieceID = pieceID
        newPiece.pieceImageNo = pieceImageNo

        let fetchRequest: NSFetchRequest<StorageEntity> = StorageEntity.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "location == %@",                        selectedStorageLocation)

        do {
            let storageEntities = try managedObjectContext.fetch(fetchRequest)
            if let selectedStorage = storageEntities.first {
                newPiece.storage = selectedStorage
                print("Selected Storage: \(selectedStorage.location ?? "Unknown")")
            } else {
                print("Selected Storage not found.")
            }
        } catch {
            print("Error fetching data: \(error)")
        }
        
        print("selectedStorage after newPiece: \(selectedStorageLocation)")
        print("newPiece.storage.location: \(newPiece.storage!.location ?? "-")")

        //Save the managed object context
        do {
            print("try managedObjectContext!.save()")
            try managedObjectContext!.save()
        } catch {
            print("Error saving data: \(error)")
        }
    }
}

extension AddPieceViewController: NSFetchedResultsControllerDelegate {
    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        addPieceTableView.beginUpdates()
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
                    didChange anObject: Any,
                    at indexPath: IndexPath?,
                    for type: NSFetchedResultsChangeType,
                    newIndexPath: IndexPath?) {
        switch type {
        case .insert:
            if let newIndexPath = newIndexPath {
                addPieceTableView.insertRows(at: [newIndexPath], with: .automatic)
            }
        case .delete:
            if let indexPath = indexPath {
                addPieceTableView.deleteRows(at: [indexPath], with: .automatic)
            }
        case .update:
            if let indexPath = indexPath {
                addPieceTableView.reloadRows(at: [indexPath], with: .automatic)
            }
        case .move:
            if let indexPath = indexPath, let newIndexPath = newIndexPath {
                addPieceTableView.deleteRows(at: [indexPath], with: .automatic)
                addPieceTableView.insertRows(at: [newIndexPath], with: .automatic)
            }
        @unknown default:
            break
        }
    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        addPieceTableView.endUpdates()
    }
}

extension AddPieceViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        print("*- numberOfSections")
        //return fetchedResultsController.sections?.count ?? 0
        let sectionCount = fetchedResultsController.sections?.count ?? 0
        print("Number of Sections: \(sectionCount)")
        return sectionCount
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let sectionInfo = fetchedResultsController.sections?[section] {
            return sectionInfo.numberOfObjects
        }
        return 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("*- indexPath.row: \(indexPath.row)")
               
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "PieceTableViewCell", for: indexPath) as? PieceTableViewCell else {
            fatalError("Unexpected Index Path for let cell")
        }
        let item = fetchedResultsController.object(at: indexPath)
        
        print("cell: \(cell)")
        print("item.description: \(String(describing: item.description))")
        print("item.pieceImageNo: \(String(describing: item.pieceImageNo))")

        cell.pieceDescriptionRecordLabel.text = item.pieceDescription
        cell.pieceIDRecordLabel.text = String(Int(item.pieceID))
        if item.pieceImageNo != nil {
            cell.pieceImageNoRecordImage?.image = UIImage(named: String(item.pieceImageNo!))
        }
        return cell
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        print("*- editingStyle")
        //MARK: to delete a row
        if editingStyle == .delete {
            let textToDelete = fetchedResultsController.object(at: indexPath)
            managedObjectContext.delete(textToDelete)
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
                fatalError("AppDelegate not found.")
            }
            appDelegate.saveContext()
        }
    }

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        print("*- titleForHeaderInSection section: \(section)")
        let sectionInfo = fetchedResultsController.sections?[section]
        print("sectionInfo.name: \(String(describing: sectionInfo?.name))")
        return sectionInfo?.name
    }
}

使用此代码,我收到失败断言错误消息。当我用sectionNameKeyPath:nil替换sectionNameKeyPath:“storage.location”时,这些片段被记录,显示没有标题部分。然后我再次运行sectionNameKeyPath:“storage.location”,一切都显示正确,但保存是不可能的。

提前感谢您的支持!

swift uitableview nsfetchedresultscontroller assertion
1个回答
0
投票
添加

self.addPieceTableView.reloadData()

在方法viewDidLoad{}的最后解决了问题。

© www.soinside.com 2019 - 2024. All rights reserved.