You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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)
}

额外优化建议

  1. 替换同步网络请求:原代码中的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()
}
  1. 彻底避免强制解包:原代码中的as? String!和try!都是风险操作,容易导致崩溃,建议始终用guard let和do-catch来处理可选值和错误。

  2. UserDefaults最佳实践:iOS10及以上版本,UserDefaults的set方法会自动完成持久化,不需要手动调用synchronize()。

内容的提问来源于stack exchange,提问作者CoderJ13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:30:42