如何监听@Published变量变化并刷新UIKit的UITableView?
解决方法
因为UIKit无法像SwiftUI那样自动响应@Published属性的变化,所以需要手动监听ViewModel的profiles数组更新,以此触发UITableView的刷新,具体配置如下:
在UIKit视图控制器中订阅ViewModel的profiles变化
给视图控制器添加AnyCancellable类型的属性存储订阅对象,防止其被提前释放。在viewDidLoad中通过Combine框架订阅viewModel.$profiles的变化,收到更新通知时调用tableView.reloadData()。
示例代码:import Combine class ProfilesViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { @ObservedObject var viewModel: ProfilesViewModel private var cancellables = Set<AnyCancellable>() private var tableView = UITableView() init(viewModel: ProfilesViewModel) { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() // 省略tableView初始化与配置代码 // 订阅profiles数组的更新 viewModel.$profiles .receive(on: DispatchQueue.main) // 确保在主线程执行UI刷新 .sink { [weak self] _ in self?.tableView.reloadData() } .store(in: &cancellables) // 初始加载数据 viewModel.getProfiles() } // 省略UITableView数据源与代理方法 }确保ViewModel的getProfiles方法正确更新profiles数组
如果getProfiles包含异步操作(比如网络请求),必须在主线程更新profiles数组,因为UI操作只能在主线程执行。示例:class ProfilesViewModel: ObservableObject { @Published var profiles: [Profile] = [] func getProfiles() { // 模拟异步数据请求 DispatchQueue.global().async { // 假设此处获取到新的profiles数据 let newProfiles = [Profile(name: "示例1"), Profile(name: "示例2")] DispatchQueue.main.async { self.profiles = newProfiles } } } }保证UIHostingController传入的是同一个ViewModel实例
创建UIHostingController展示ProfilesMenu时,必须传入和UIKit视图控制器完全相同的ViewModel对象,这样SwiftUI中调用viewModel.getProfiles才会触发同一个实例的profiles更新,进而被UIKit视图控制器的订阅监听到。示例:// 在UIKit视图控制器中创建并展示SwiftUI视图 let profilesMenu = ProfilesMenu(viewModel: viewModel) let hostingController = UIHostingController(rootView: profilesMenu) // 展示hostingController的代码,如present或添加为子控制器 present(hostingController, animated: true)
完成以上配置后,当你在ProfilesMenu中调用viewModel.getProfiles更新profiles数组时,UIKit视图控制器的订阅会收到通知,自动触发UITableView的刷新。
内容的提问来源于stack exchange,提问作者Sylar
相关产品推荐
相关产品推荐

