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

SwiftUI模态视图传数据至父视图后列表不更新问题求助

问题分析与解决办法

核心问题是父视图的状态未响应URL变化,导致数据更新后列表没有重绘。SwiftUI是数据驱动的UI框架,只有状态变量发生变化时才会触发视图刷新,结合你的场景,可按以下步骤修复:

1. 确保状态的双向绑定(模态→父视图)

父视图需用@State管理当前URL,通过@Binding传递给模态视图,让模态视图的选择能同步更新父视图的URL状态。

2. 让数据获取器响应URL变化

当URL更新时,主动触发重新请求数据,确保ObservableObject的@Published变量能更新并通知视图刷新。

完整代码示例

数据获取器(VideoFetcher)

import Foundation
import SwiftUI

struct Video: Codable, Identifiable {
    let id: String
    let title: String
    // 其他视频字段
}

class VideoFetcher: ObservableObject {
    @Published var videos: [Video] = []
    
    func fetchVideos(from urlString: String) {
        guard let url = URL(string: urlString) else {
            print("无效URL")
            return
        }
        
        URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard let data = data, error == nil else {
                print("请求失败:\(error?.localizedDescription ?? "未知错误")")
                return
            }
            
            do {
                let decodedVideos = try JSONDecoder().decode([Video].self, from: data)
                DispatchQueue.main.async {
                    self?.videos = decodedVideos
                    print("数据加载成功:\(decodedVideos.count)条")
                }
            } catch {
                print("解析失败:\(error)")
            }
        }.resume()
    }
}

父视图(VideoView)

struct VideoView: View {
    @State private var currentVideoURL = "https://初始静态URL.json"
    @State private var showCategoryModal = false
    @StateObject private var videoFetcher = VideoFetcher()
    
    var body: some View {
        List(videoFetcher.videos) { video in
            Text(video.title)
        }
        .toolbar {
            Button("切换分类") {
                showCategoryModal = true
            }
        }
        .sheet(isPresented: $showCategoryModal) {
            VideoCategory(selectedURL: $currentVideoURL)
        }
        // 监听URL变化,触发重新请求
        .onChange(of: currentVideoURL) { newURL in
            videoFetcher.fetchVideos(from: newURL)
        }
        // 初始加载数据
        .onAppear {
            videoFetcher.fetchVideos(from: currentVideoURL)
        }
    }
}

模态分类视图(VideoCategory)

struct VideoCategory: View {
    @Binding var selectedURL: String
    @Environment(\.dismiss) private var dismiss
    
    // 模拟分类列表
    let categoryURLs = [
        "搞笑视频": "https://example.com/comedy.json",
        "科技视频": "https://example.com/tech.json",
        "美食视频": "https://example.com/food.json"
    ]
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(Array(categoryURLs.keys), id: \.self) { categoryName in
                    Button(categoryName) {
                        selectedURL = categoryURLs[categoryName]!
                        dismiss()
                    }
                }
            }
            .navigationTitle("选择分类")
            .toolbar {
                Button("取消") {
                    dismiss()
                }
            }
        }
    }
}

关键注意点

  • @StateObject的使用:用来持有VideoFetcher实例,确保视图生命周期内对象不会被重复创建,保证数据的连续性。
  • @Binding双向绑定:模态视图通过绑定直接修改父视图的currentVideoURL状态,触发后续的onChange回调。
  • 主线程更新UI:数据解析完成后必须在主线程更新@Published变量,否则视图无法接收到更新通知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 01:45:11