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

Swift实现委托模式时WeatherManager的delegate始终为nil

问题原因

delegate始终为nil的核心原因是你创建了两个完全独立的WeatherManager实例,设置delegate和发起网络请求根本不是同一个对象:

  • WeatherViewController中声明的let weatherManager = WeatherManager()实例,你在viewDidLoad里确实给它设置了delegate为当前控制器,但这个实例全程没有被调用过fetchWeather方法,完全闲置。
  • CoordinateManager中声明的let weathetManager = WeatherManager()是一个全新的独立实例,你实际拼接完天气URL后发起请求用的是这个实例,这个实例的delegate属性从未被赋值,自然为nil,回调无法触发。
    另外注意这里weathetManager存在拼写错误(漏了字母r),后续维护容易踩坑。
修复步骤
  1. 移除CoordinateManager内部自行创建的WeatherManager实例,改为接收外部传入的、已经绑定好delegate的实例:
    struct CoordinateManager {
        // 移除原有的let weathetManager = WeatherManager()
        var weatherManager: WeatherManager
        let coordinateURL = "https://api.openweathermap.org/geo/1.0/direct?limit=1&appid=c8e60c6317c653a1789294c00f54ae19"
    
        init(weatherManager: WeatherManager) {
            self.weatherManager = weatherManager
        }
    
        // 其余原有方法保持不变,仅把parseJSON方法里调用的weathetManager改为self.weatherManager
        func parseJSON(JSONobject: Data) {
            let decoder = JSONDecoder()
            do {
                let decodedData = try decoder.decode([CoordinateData].self, from: JSONobject)
                let name = decodedData[0].name
                let lat = decodedData[0].lat
                let lon = decodedData[0].lon
                
                let coordinateModel = CoordinateModel(name: name, lat: lat, lon: lon)
                let weatherURL = coordinateModel.urlString
                // 改为用传入的weatherManager发起请求
                self.weatherManager.fetchWeather(urlString: weatherURL)
            } catch {
                print(error)
            }
        }
    
        // ...... 其余CoordinateManager原有方法不变
    }
    
  2. 在WeatherViewController中初始化CoordinateManager时,把当前控制器持有的、已经绑定好delegate的weatherManager实例传入:
    class WeatherViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate {
        // ...... 原有IBOutlet保持不变
        let weatherManager = WeatherManager()
        var coordinateManager: CoordinateManager!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            searchTextField.delegate = self
            searchTextField.keyboardType = .asciiCapable
            weatherManager.delegate = self
            // 传入已绑定delegate的weatherManager实例
            coordinateManager = CoordinateManager(weatherManager: weatherManager)
        }
    
        // ...... 其余原有方法不变
    }
    
补充优化

didUpdateWeather回调是在URLSession的后台子线程执行的,如果回调内需要更新UI,必须手动切换到主线程,否则会出现UI更新延迟、偶现崩溃的问题:

func didUpdateWeather(inputWeatherModel: WeatherModel) {
    DispatchQueue.main.async {
        print(inputWeatherModel.temperature)
        // 此处编写温度标签、城市名、天气图标的UI更新逻辑
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:12:12