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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:56:01