使用SJSegmentedController切换分段后重新加载TableView的问题
解决分段切换时TableView无法重新加载数据的问题
核心问题在于:你的带TableView的ViewController在首次加载后,viewDidLoad和viewDidAppear只会执行一次,切换分段时不会再次触发,所以仅靠这两个生命周期方法无法重新加载数据。我们需要在didMoveToPage触发时,主动通知目标ViewController刷新数据。
下面是两种简单可行的解决方案,优先推荐第一种:
方案一:直接获取目标VC实例并调用刷新方法
这种方法最直接,因为didMoveToPage方法已经给了你当前显示的controller实例,我们只需要判断它是你的TableView所在VC,然后调用公开的刷新方法即可。
步骤1:修改带TableView的ViewController,添加公开的刷新方法
首先,给你的第二个ViewController添加一个可以被外部调用的刷新方法,用来触发数据重新加载:
class DealTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { // 你的其他属性(比如values、tableView) override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) tableView.reloadData() } // 保持原有的get方法,但确保它可以被内部调用 func get() { // 优化:用guard let避免强制解包 guard let dealsPHP = UserDefaults.standard.string(forKey: "DealsPHP"), let url = URL(string: dealsPHP) else { print("无法获取有效接口地址") return } if let data = try? Data(contentsOf: url) { do { self.values = try JSONSerialization.jsonObject(with: data, options: []) as! NSArray // 确保在主线程更新UI DispatchQueue.main.async { self.tableView.reloadData() } } catch { print("JSON解析失败:\(error)") } } else { DispatchQueue.main.async { self.showNoInternetAlert() } } } // 添加公开的刷新方法,供外部调用 func refreshData() { get() } // 把弹窗逻辑抽成单独方法,提升复用性 private func showNoInternetAlert() { let alertController = UIAlertController(title: "No Internet Connection", message: "It looks like you aren't connected to the Internet. Please check your internet connection and try again.", preferredStyle: .alert) let okAction = UIAlertAction(title: "Try Again", style: .default) { _ in self.get() } alertController.addAction(okAction) self.present(alertController, animated: true) } }
步骤2:在didMoveToPage中调用刷新方法
回到第一个ViewController的didMoveToPage方法,设置完UserDefaults后,判断当前的controller是不是你的TableViewVC,然后调用refreshData():
func didMoveToPage(_ controller: UIViewController, segment: SJSegmentTab?, index: Int) { if selectedSegment != nil { selectedSegment?.titleColor(.gray) } if segments.count > 0 { selectedSegment = segments[index] } // 根据选中分段修改对应的PHP接口 let currSeg = index print(currSeg) // 优化:去掉不必要的synchronize(),iOS10+不需要手动调用 switch currSeg { case 0: UserDefaults.standard.set("xyz.php", forKey: "DealsPHP") case 2: UserDefaults.standard.set("uys.php", forKey: "DealsPHP") case 3: UserDefaults.standard.set("wrt.php", forKey: "DealsPHP") default: // 处理index=1的情况,比如设置默认接口或留空 break } // 关键:调用目标VC的刷新方法,触发数据重新加载 if let dealVC = controller as? DealTableViewController { dealVC.refreshData() } }
方案二:使用NotificationCenter通知(适合VC之间没有直接引用的场景)
如果你的分段控制器和TableViewVC之间没有直接的实例引用,可以用通知中心来传递刷新信号:
步骤1:在TableViewVC中注册通知
class DealTableViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 注册刷新通知 NotificationCenter.default.addObserver(self, selector: #selector(refreshData), name: NSNotification.Name("RefreshDealData"), object: nil) } deinit { // 记得移除通知,避免内存泄漏 NotificationCenter.default.removeObserver(self) } @objc private func refreshData() { get() } // 其他代码和方案一相同 }
步骤2:在didMoveToPage中发送通知
func didMoveToPage(_ controller: UIViewController, segment: SJSegmentTab?, index: Int) { // 原有的设置UserDefaults代码... // 发送刷新通知,触发TableView数据重新加载 NotificationCenter.default.post(name: NSNotification.Name("RefreshDealData"), object: nil) }
额外优化建议
- 替换同步网络请求:原代码中的
Data(contentsOf: url!)是同步请求,会阻塞主线程导致UI卡顿,建议改成异步的URLSession请求,示例代码如下:
func get() { guard let dealsPHP = UserDefaults.standard.string(forKey: "DealsPHP"), let url = URL(string: dealsPHP) else { return } let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } if let error = error { print("网络请求错误:\(error)") DispatchQueue.main.async { self.showNoInternetAlert() } return } guard let data = data else { DispatchQueue.main.async { self.showNoInternetAlert() } return } do { if let values = try JSONSerialization.jsonObject(with: data, options: []) as? NSArray { self.values = values DispatchQueue.main.async { self.tableView.reloadData() } } } catch { print("JSON解析错误:\(error)") DispatchQueue.main.async { // 可以显示解析失败的提示弹窗 } } } task.resume() }
彻底避免强制解包:原代码中的
as? String!和try!都是风险操作,容易导致崩溃,建议始终用guard let和do-catch来处理可选值和错误。UserDefaults最佳实践:iOS10及以上版本,
UserDefaults的set方法会自动完成持久化,不需要手动调用synchronize()。
内容的提问来源于stack exchange,提问作者CoderJ13
相关产品推荐
相关产品推荐

