大家好!
使用 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”,一切都显示正确,但保存是不可能的。
提前感谢您的支持!
self.addPieceTableView.reloadData()在方法viewDidLoad{}的最后解决了问题。