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

SwiftUI视图未更新:调用含@Published属性的函数无响应

问题根源与解决方案

核心问题:重复创建ViewModel实例

你在DiscoverView里同时生成了两个完全独立的DiscoverViewModel对象:

  • 用@StateObject var viewModel = DiscoverViewModel()创建的实例,是父视图列表绑定的数据源
  • 但通过.environmentObject(DiscoverViewModel())注入给子视图的是另一个全新实例
    这就导致子视图修改筛选条件时,根本没影响到父视图绑定的那个ViewModel,自然列表不会更新。

修复步骤

1. 统一ViewModel实例

删除DiscoverView中重复创建的.environmentObject(DiscoverViewModel()),替换为注入已有的viewModel实例:

struct DiscoverView: View {
    @EnvironmentObject var navigation: NavigationManager
    @StateObject var viewModel = DiscoverViewModel()

    var body: some View {
        NavigationStack(path: $navigation.discoverStack) {
            ScrollView {
                VStack {
                    DiscoverFiltersControls()
                    ForEach(viewModel.trendingShows) { show in
                        Text(show.title)
                    }
                }
                .padding(.vertical)
            }
            .scrollIndicators(.hidden)
            .navigationTitle("Discover")
            .toolbar { ProfileToolbar() }
        }
        // 注入已创建的viewModel,而非新实例
        .environmentObject(viewModel)
    }
}

2. 补全Genre筛选的触发逻辑

当前选择Genre后没有调用getTrendingShows(),需要在DiscoverFiltersControls中添加监听:

// 放在typeFilters的onChange代码块之后
.onChange(of: viewModel.selectedGenre) {
    viewModel.getTrendingShows()
}

同时要在getTrendingShows()里加入Genre筛选的逻辑(否则选了Genre也不会过滤结果):

func getTrendingShows() {
    Task {
        let isFiltered = !self.typeFilters.isEmpty && self.typeFilters.count != ShowType.allCases.count
        let endpoint: TrendingEndpoint = !isFiltered
            ? .all
            : self.typeFilters.contains(.movie) ? .movies : .tvSeries
        
        var shows = try await TMDbManager.shared.trending(endpoint).toShows()
        
        // 新增Genre过滤
        if let selectedGenre = self.selectedGenre {
            shows = shows.filter { $0.genreIds.contains(selectedGenre.id) }
        }
        
        self.trendingShows = shows
    }
}

3. 确保ForEach的数据源合规

SwiftUI的ForEach要求元素遵循Identifiable协议,或者显式指定id参数。如果Show结构体还没实现Identifiable,修改ForEach代码:

ForEach(viewModel.trendingShows, id: \.id) { show in
    Text(show.title)
}

内容的提问来源于stack exchange,提问作者Curt Orion-Indev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:54:58