如何通过Navigation Controller在视图间传递并操作Core Data对象
解决纯代码导航下Core Data对象在视图控制器间的传递与修改问题
问题背景
我需要在UITableView的didSelectRowAt方法中把Core Data对象传递给另一个视图控制器,目前能通过navigationController?.pushViewController实现页面跳转,但不清楚不使用Storyboard、纯代码加载视图的场景下如何传值,同时要在第二个控制器中访问并修改这个Core Data对象。现有代码如下:
第一个视图控制器(含UITableView)
var items = [Item]() // Core Data实体数组 ... override func viewWillAppear(_ animated: Bool) { items = DBManager.share.fetchItems() homeTableView.reloadData() } extension FirstVC : UITableViewDelegate, UITableViewDataSource { ... func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "homeCell", for: indexPath) as? HomeTableCell else { return UITableViewCell() } let newItem = items[indexPath.row] cell.homeCellTitle.text = newItem.title cell.homeCellPrice.text = newItem.price cell.homeCellPost?.text = newItem.post return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedItem = self.items[indexPath.row] guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") as? SecondVC else {return} self.navigationController?.pushViewController(vc, animated: true) } }
第二个视图控制器
class SecondVC: UIViewController { var selectedItem: Item? override func viewDidLoad() { super.viewDidLoad() } @IBAction func editButtonPressed(_ sender: Any) { // 不知道如何修改Core Data对象 } }
DBManager(Core Data管理类)
import UIKit import CoreData class DBManager{ static let share = DBManager() // MARK: - Core Data stack lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "RC_week3") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() // MARK: - Core Data Saving support lazy var context = persistentContainer.viewContext func saveContext () { if context.hasChanges { do{ try context.save() } catch { let nserror = error as NSError fatalError("Unresolved error \(nserror), \(nserror.userInfo)") } } } func fetchItems() -> [Item] { var Items = [Item]() let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: Item.description()) do{ Items = try context.fetch(fetchRequest) as! [Item] }catch{ print("fetching error") } return Items } }
解决方案
1. 纯代码初始化第二个VC并传递Core Data对象
修改第一个VC的didSelectRowAt方法,直接通过代码初始化SecondVC,并给其selectedItem属性赋值(Core Data对象是引用类型,传递后两个VC操作的是同一个实例):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedItem = self.items[indexPath.row] // 纯代码初始化第二个VC,替代Storyboard实例化方式 let vc = SecondVC() // 传递选中的Core Data对象 vc.selectedItem = selectedItem self.navigationController?.pushViewController(vc, animated: true) }
2. 在第二个VC中修改Core Data对象并保存
在editButtonPressed方法中直接修改selectedItem的属性,调用DBManager的saveContext()方法即可将修改同步到数据库:
class SecondVC: UIViewController { var selectedItem: Item? override func viewDidLoad() { super.viewDidLoad() // 可选:在这里将selectedItem的现有数据展示到UI组件(如文本框) } @IBAction func editButtonPressed(_ sender: Any) { guard let item = selectedItem else { return } // 修改Core Data对象的属性 item.title = "更新后的标题" item.price = "更新后的价格" item.post = "更新后的内容" // 保存上下文,同步修改到数据库 DBManager.share.saveContext() // 保存完成后返回上一页 navigationController?.popViewController(animated: true) } }
3. 返回第一个VC后刷新数据
第一个VC的viewWillAppear方法已经实现了重新获取数据并刷新表格,保留即可确保返回后能看到修改后的内容:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) items = DBManager.share.fetchItems() homeTableView.reloadData() }
额外提示
- Core Data对象是引用类型,传递后无需通过ID重新查询,直接修改即可
- 如果需要更健壮的错误处理,可以修改DBManager的
saveContext()方法,替换fatalError为打印错误或弹出提示 - 确保
Item实体的属性类型与修改时赋值的类型一致(如title为String类型)
内容的提问来源于stack exchange,提问作者plzhelpme
相关产品推荐
相关产品推荐

