Swift 5中如何从Controller B刷新Controller A的TableView?
这是iOS开发里非常常见的跨控制器数据同步需求,我给你整理了三种实用的实现方案,你可以根据自己的场景来选:
方法一:使用闭包(Closure)
这种方式代码简洁,适合简单的一对一通信场景,直接把刷新逻辑“传递”给弹窗控制器。
步骤:
- 在Controller B(
EnterQTYView)里定义一个闭包属性,用来传递提交后的响应数据 - 在Controller A弹出弹窗时,给这个闭包赋值,写入刷新TableView的逻辑
- Controller B提交成功后,调用闭包并传入响应字典
修改后的Controller B代码:
class EnterQTYView: UIViewController { // 定义闭包,参数为提交后返回的字典 var onSubmitSuccess: (([String: Any]) -> Void)? // 提交按钮点击事件(假设你已经关联了这个方法) @IBAction func submitButtonTapped(_ sender: UIButton) { // 这里替换成你实际获取响应字典的逻辑 let responseDict: [String: Any] = ["qty": "10", "status": "success"] // 调用闭包,把数据传递给Controller A onSubmitSuccess?(responseDict) // 关闭弹窗 dismiss(animated: true, completion: nil) } }
修改后的Controller A代码:
func btnQTYClickedFromcell(selectedIP: IndexPath) { let storyboard = UIStoryboard(name: "Dashboard", bundle: nil) // 这里要强制转成EnterQTYView类型,才能访问闭包属性 guard let myAlert = storyboard.instantiateViewController(withIdentifier: "EnterQTYView") as? EnterQTYView else { return } myAlert.modalPresentationStyle = .overCurrentContext myAlert.modalTransitionStyle = .crossDissolve // 给闭包赋值,处理返回的数据并刷新TableView myAlert.onSubmitSuccess = { [weak self] responseDict in // 1. 先用responseDict更新你的数据源(比如self?.dataArray = 处理后的数据) // 2. 刷新TableView self?.tableView.reloadData() } self.present(myAlert, animated: true, completion: nil) }
方法二:使用代理(Delegate)
这种方式更符合iOS的设计规范,适合需要多个交互回调的复杂场景,代码可读性和扩展性更好。
步骤:
- 定义一个协议,包含提交成功的回调方法
- Controller B里定义代理属性
- Controller A遵守该协议并实现回调方法
- 弹出弹窗时设置Controller A为代理
- Controller B提交成功后调用代理方法
第一步:定义协议
// 定义代理协议,注意用AnyObject保证只能被类遵守 protocol EnterQTYViewDelegate: AnyObject { func enterQTYViewDidSubmit(with responseDict: [String: Any]) }
修改后的Controller B代码:
class EnterQTYView: UIViewController { // 代理属性必须用weak,避免循环引用 weak var delegate: EnterQTYViewDelegate? @IBAction func submitButtonTapped(_ sender: UIButton) { let responseDict: [String: Any] = ["qty": "10", "status": "success"] // 调用代理方法传递数据 delegate?.enterQTYViewDidSubmit(with: responseDict) dismiss(animated: true, completion: nil) } }
修改后的Controller A代码:
// 让Controller A遵守代理协议 class ControllerA: UIViewController, EnterQTYViewDelegate { // ... 你的其他现有代码 func btnQTYClickedFromcell(selectedIP: IndexPath) { let storyboard = UIStoryboard(name: "Dashboard", bundle: nil) guard let myAlert = storyboard.instantiateViewController(withIdentifier: "EnterQTYView") as? EnterQTYView else { return } myAlert.modalPresentationStyle = .overCurrentContext myAlert.modalTransitionStyle = .crossDissolve // 设置代理为当前Controller A myAlert.delegate = self self.present(myAlert, animated: true, completion: nil) } // 实现代理方法 func enterQTYViewDidSubmit(with responseDict: [String: Any]) { // 更新数据源 // self?.dataArray = ... // 刷新TableView tableView.reloadData() } }
方法三:使用通知中心(NotificationCenter)
这种方式适合跨多层控制器、或者多个地方需要监听提交事件的场景,但要注意内存管理,避免内存泄漏。
步骤:
- 定义一个自定义通知名称
- Controller A添加通知观察者,监听该通知
- Controller B提交成功后发送通知,携带响应字典
- Controller A收到通知后刷新TableView
- 在Controller A销毁时移除观察者
第一步:定义通知名称
// 用extension封装通知名称,更规范 extension Notification.Name { static let qtySubmitted = Notification.Name("qtySubmittedNotification") }
修改后的Controller A代码:
class ControllerA: UIViewController { // ... 其他现有代码 override func viewDidLoad() { super.viewDidLoad() // 添加通知观察者 NotificationCenter.default.addObserver( self, selector: #selector(handleQTYSubmitted(_:)), name: .qtySubmitted, object: nil ) } // 页面销毁时移除观察者,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } func btnQTYClickedFromcell(selectedIP: IndexPath) { let storyboard = UIStoryboard(name: "Dashboard", bundle: nil) let myAlert = storyboard.instantiateViewController(withIdentifier: "EnterQTYView") myAlert.modalPresentationStyle = .overCurrentContext myAlert.modalTransitionStyle = .crossDissolve self.present(myAlert, animated: true, completion: nil) } // 处理通知的方法 @objc func handleQTYSubmitted(_ notification: Notification) { // 从通知里取出响应字典 if let responseDict = notification.userInfo as? [String: Any] { // 更新数据源 // self?.dataArray = ... // 刷新TableView tableView.reloadData() } } }
修改后的Controller B代码:
@IBAction func submitButtonTapped(_ sender: UIButton) { let responseDict: [String: Any] = ["qty": "10", "status": "success"] // 发送通知,携带响应字典 NotificationCenter.default.post( name: .qtySubmitted, object: nil, userInfo: responseDict ) dismiss(animated: true, completion: nil) }
方案选择建议:
- 如果只是简单的提交后刷新,优先选闭包,代码最简洁
- 如果需要多个回调交互(比如取消、编辑等),选代理,结构更清晰
- 如果需要跨多层控制器或者多个页面监听事件,再考虑通知中心
内容的提问来源于stack exchange,提问作者Tushar Khopade
相关产品推荐
相关产品推荐

