Swift 4中如何在UITableView滑动删除时删除CoreData对象?
解决CoreData条目与UITableView行同步删除的问题
看起来你已经搞定了CoreData的读写,但滑动删除时只处理了数组,没同步到CoreData对吧?核心问题在于你当前的数组只存储了Date值,没有保留CoreData中对应的NSManagedObject实例,所以删除时找不到要移除的实体对象。下面给你两种解决方案,推荐第一种更稳妥的方式:
方案一:让数组存储CoreData实体对象(推荐)
这种方法直接把CoreData查询到的NSManagedObject存在数组里,删除时可以直接拿到对应的实体进行操作,既高效又能避免重复日期的问题。
步骤1:修改数组类型
把原来的sittingsDatesArr改成存储NSManagedObject的数组:
var sittingsArr: [NSManagedObject] = []
步骤2:更新getData函数
直接将CoreData查询结果赋值给数组,不用单独提取Date:
func getData() { let appDelegate = UIApplication.shared.delegate as! AppDelegate let context = appDelegate.persistentContainer.viewContext let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Sittings") request.returnsObjectsAsFaults = false do { let results = try context.fetch(request) if results.count > 0 { sittingsArr = results as! [NSManagedObject] } else { print("database is empty") } } catch { print("error fetching data: \(error)") } }
步骤3:更新UITableView数据源方法
在cellForRowAt中从数组取实体,再提取日期显示:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "你的CellID", for: indexPath) let sitting = sittingsArr[indexPath.row] if let sittingDate = sitting.value(forKey: "date") as? Date { dateFormatter.dateStyle = .long dateFormatter.timeStyle = .long cell.textLabel?.text = dateFormatter.string(from: sittingDate) } return cell }
步骤4:完善滑动删除逻辑
直接从数组拿到要删除的实体,从CoreData上下文删除并保存:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { let appDelegate = UIApplication.shared.delegate as! AppDelegate let context = appDelegate.persistentContainer.viewContext // 获取要删除的CoreData实体 let sittingToDelete = sittingsArr[indexPath.row] // 从上下文删除 context.delete(sittingToDelete) do { // 保存上下文,提交删除操作 try context.save() print("-----DELETED SUCCESSFULLY-----") } catch { print("XXXXX ERROR DELETING: \(error) XXXXXXX") } // 从数组移除元素并刷新对应行 sittingsArr.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .automatic) } }
方案二:通过日期查询并删除(适合不想改动现有数组结构)
如果你不想修改数组的存储类型,依然用Date数组,可以通过日期匹配查询对应的CoreData实体再删除。但要注意:如果有多个相同日期的条目,这种方法会删除第一个匹配的条目,若要处理重复日期,建议给Sittings实体添加唯一标识字段。
修改滑动删除代码如下:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { let appDelegate = UIApplication.shared.delegate as! AppDelegate let context = appDelegate.persistentContainer.viewContext // 获取要删除的日期 let dateToDelete = sittingsDatesArr[indexPath.row] // 创建查询请求,匹配date字段 let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Sittings") request.predicate = NSPredicate(format: "date == %@", dateToDelete as CVarArg) request.returnsObjectsAsFaults = false do { let results = try context.fetch(request) if let sittingToDelete = results.first as? NSManagedObject { context.delete(sittingToDelete) try context.save() print("-----DELETED SUCCESSFULLY-----") } } catch { print("XXXXX ERROR DELETING: \(error) XXXXXXX") } // 从数组移除并刷新表格 sittingsDatesArr.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .automatic) } }
小提示
原来的refresh函数会重新调用getData加载整个数组,用方案一的话,删除后直接更新数组和表格行即可,不需要调用refresh,这样更高效。如果有其他地方修改CoreData数据的场景,refresh还是可以保留用来同步数组和UI。
内容的提问来源于stack exchange,提问作者Bigdadda06
相关产品推荐
相关产品推荐

