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

SwiftUI中如何通过TextField修改WeatherClass的city变量

解决方案

核心问题分析

你的代码存在两个关键问题:

  1. WeatherClass的city变量未标记为@Published,无法被SwiftUI观察到变化;
  2. cityTextField的@State是局部状态,和WeatherClass的city没有任何关联,输入内容无法同步到ViewModel。

修改后的完整代码

1. 更新WeatherClass

class WeatherClass: ObservableObject {
    @Published var weatherAddress: String = ""
    @Published var weatherDays: [WeatherDays] = []
    @Published var city: String = "" // 改为@Published,让SwiftUI能观察到变化
  
    func fetch() {
        guard !city.isEmpty else { return } // 空城市名不发起请求
        let location = city
        let apiKey = "AP8LUYMSTHZ"
        
        // 安全创建URL,避免强制解包崩溃
        guard let url = URL(string: "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/\(location)?key=\(apiKey)") else {
            print("无效的城市URL")
            return
        }
        
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { 
                print("未获取到数据")
                return 
            }
                
            // 用do-catch捕获解析错误,方便调试
            do {
                let weather = try JSONDecoder().decode(WeatherData.self, from: data)
                DispatchQueue.main.async {
                    self.weatherAddress = weather.resolvedAddress
                    self.weatherDays = weather.days
                }
            } catch {
                print("JSON解析失败: \(error.localizedDescription)")
            }
        }.resume()
    }
}

struct WeatherData: Decodable {
    let resolvedAddress: String
    let days: [WeatherDays]
}

struct WeatherDays: Hashable, Decodable {
    let datetime: String
    let tempmax: Double
    let tempmin: Double
    let description: String
}

2. 重构CityTextField视图

struct CityTextField: View { // 遵循Swift命名规范,首字母大写
    @ObservedObject var weatherVM: WeatherClass
    var onSearch: () -> Void // 搜索触发回调
    
    var body: some View {
        HStack {
            TextField("搜索城市", text: $weatherVM.city)
                .frame(height:30)
                .multilineTextAlignment(.center)
                .background(Color.gray.opacity(0.2))
                .cornerRadius(25)
                .padding(.horizontal)
                .onSubmit { // 回车时触发搜索
                    onSearch()
                }
            
            // 新增搜索按钮,手动触发请求
            Button(action: onSearch) {
                Image(systemName: "magnifyingglass")
                    .foregroundColor(.blue)
            }
            .padding(.trailing)
        }
    } 
}

3. 主视图使用示例

struct ContentView: View {
    // iOS 14+用@StateObject创建ObservableObject实例
    @StateObject private var weatherVM = WeatherClass()
    
    var body: some View {
        VStack(spacing: 20) {
            CityTextField(weatherVM: weatherVM) {
                weatherVM.fetch()
            }
            
            // 显示解析后的城市地址
            if !weatherVM.weatherAddress.isEmpty {
                Text("当前城市: \(weatherVM.weatherAddress)")
                    .font(.headline)
            }
            
            // 显示天气列表
            List(weatherVM.weatherDays, id: \.self) { day in
                VStack(alignment: .leading, spacing: 4) {
                    Text(day.datetime)
                        .font(.subheadline)
                        .foregroundColor(.gray)
                    Text("最高温: \(day.tempmax)° / 最低温: \(day.tempmin)°")
                    Text(day.description)
                        .font(.caption)
                }
                .padding(.vertical, 8)
            }
        }
        .padding(.top)
    }
}

关键修改说明

  • @Published标记city:让WeatherClass的city变量变化时,自动通知所有绑定的视图更新;
  • 视图与ViewModel绑定:CityTextField通过@ObservedObject接收WeatherClass实例,直接将TextField的文本绑定到weatherVM.city,实现输入内容同步;
  • 安全处理URL和解析:替换强制解包为可选绑定,用do-catch捕获解析错误,避免崩溃并方便调试;
  • 触发搜索的方式:同时支持回车触发和按钮触发,提升用户体验;
  • 遵循Swift命名规范:结构体/类名首字母大写,代码更易读。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:25:19