UIKit中无法接收SwiftUI视图数组更新问题求助
问题:SwiftUI视图更新无法通过Publisher同步到UIKit环境
通过UIHostingController将SwiftUI视图集成到UIKit项目中,点击Tile视图会增加其counter计数,但UIKit端无法通过Publisher接收到该更新。
问题根源
tiles.publisher是Sequence Publisher,仅会在订阅时一次性发送数组中的所有初始元素,不会监听单个Tile对象内部@Published属性的变化。- 未针对每个
Tile的counter属性设置订阅,因此SwiftUI中修改tile.counter时,UIKit端无法感知状态变化。
解决方案
方案一:直接订阅每个Tile的@Published属性
修改UIKit的ViewController代码,在创建Tile实例后,单独订阅每个Tile的$counter Publisher:
import UIKit import SwiftUI import Combine class ViewController: UIViewController { var cancelablesSet:[AnyCancellable] = [] var tiles:[ Tile] = [] override func viewDidLoad() { super.viewDidLoad() for i in 0...3{ let aTile = Tile(counter: 0, index: i ) tiles.append( aTile ) // 订阅当前tile的counter变化 aTile.$counter .sink(receiveValue: { newCount in print("updated tile at index:\(aTile.index) to value:\(newCount)") }) .store(in: &cancelablesSet ) } let testVC = UIHostingController(rootView: TilesView(tiles: tiles ) ) addChild(testVC) // 修正原拼写错误 addChildViewContorller testVC.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ testVC.view.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor ), testVC.view.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor ), testVC.view.topAnchor.constraint(equalTo: view.topAnchor ), testVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor ), ]) testVC.didMove(toParent: self) // 补全子控制器生命周期调用 } }
方案二:使用统一ViewModel管理状态(推荐复杂场景)
创建ViewModel类统一管理所有Tile,通过ViewModel的Publisher集中传递状态更新:
// 新增ViewModel类 class TileViewModel: ObservableObject { @Published var tiles: [Tile] = [] init() { for i in 0...3 { tiles.append(Tile(counter: 0, index: i)) } } // 封装订阅逻辑,返回Tile的索引和计数器更新 func tileUpdatePublisher() -> AnyPublisher<(index: Int, counter: Int), Never> { tiles.publisher .flatMap { tile in tile.$counter .map { (tile.index, $0) } } .eraseToAnyPublisher() } } // 修改ViewController class ViewController: UIViewController { var cancelablesSet:[AnyCancellable] = [] let viewModel = TileViewModel() override func viewDidLoad() { super.viewDidLoad() let testVC = UIHostingController(rootView: TilesView(tiles: viewModel.tiles ) ) addChild(testVC) testVC.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ testVC.view.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor ), testVC.view.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor ), testVC.view.topAnchor.constraint(equalTo: view.topAnchor ), testVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor ), ]) testVC.didMove(toParent: self) // 订阅ViewModel的状态更新 viewModel.tileUpdatePublisher() .sink(receiveValue: { update in print("updated tile at index:\(update.index) to value:\(update.counter)") }) .store(in: &cancelablesSet ) } }
内容的提问来源于stack exchange,提问作者reza23
相关产品推荐
相关产品推荐

