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

Swift天气应用中如何正确稳定显示天气图标?

解决Swift天气App图标不稳定显示的问题

嘿,我仔细看了你的问题和代码片段,图标偶尔显示不稳定的情况,主要问题出在图片加载的异步处理方式以及UI更新的线程使用上,咱们一步步来修复:

问题分析

  1. 你用了全局变量image来存储图片对象,这种方式很容易在多线程场景下出现赋值不及时或者被覆盖的情况,导致UI更新时拿到的图片可能是空的或者旧的。
  2. 使用DispatchQueue.main.sync来更新UI是非常危险的——如果当前代码已经运行在主线程,调用sync会直接造成死锁,阻塞UI刷新,这也是图标偶尔不显示的重要原因。
  3. 接口返回的图标URL是//cdn.apixu.com/...这种相对协议的格式,直接用这个URL可能会因为协议缺失导致部分场景下加载失败。

解决方案

1. 修复图片URL的协议问题

先把接口返回的图标URL补全成完整的HTTPS链接:

// 假设你从JSON里拿到的图标字段是iconString
let iconString = "//cdn.apixu.com/weather/64x64/day/113.png"
let fullIconURL = URL(string: "https:" + iconString)!

2. 异步加载图片+主线程安全更新UI

不要用全局变量存图片,而是直接在异步下载完成后更新UIImageView,这样能保证图片加载完成后才更新UI:

// 替换你原来的图片加载逻辑
URLSession.shared.dataTask(with: fullIconURL) { data, response, error in
    // 检查请求是否成功
    guard let imageData = data, error == nil else {
        print("图片加载失败:\(error?.localizedDescription ?? "未知错误")")
        return
    }
    // 必须回到主线程更新UI控件
    DispatchQueue.main.async {
        self.imageView.image = UIImage(data: imageData)
    }
}.resume()

3. 替换错误的main.sync为main.async

你原来的UI更新代码里用了DispatchQueue.main.sync,这会导致主线程阻塞,改成async才能安全更新UI:

// 替换成这样的UI更新逻辑
DispatchQueue.main.async {
    if errorHasOccured {
        self?.cityLabel.text = "Unknown city"
        self?.temperatureLabel.text = ""
        self?.imageView.image = nil // 出错时清空图标
    } else {
        self?.cityLabel.text = locationName
        self?.temperatureLabel.text = "\(temperature!)"
        // 这里不再用全局image,而是用上面异步加载好的图片
    }
}

4. 加入图片缓存提升稳定性(可选但推荐)

为了避免重复下载相同的图标,同时提升显示速度,可以用NSCache做图片缓存:

// 在类里定义一个缓存对象
let imageCache = NSCache<NSString, UIImage>()

// 加载图片时先检查缓存
func loadWeatherIcon(with urlString: String) {
    let fullURLString = "https:" + urlString
    // 先查缓存
    if let cachedImage = imageCache.object(forKey: fullURLString as NSString) {
        DispatchQueue.main.async {
            self.imageView.image = cachedImage
        }
        return
    }
    // 没有缓存再下载
    guard let url = URL(string: fullURLString) else { return }
    URLSession.shared.dataTask(with: url) { data, _, error in
        guard let data = data, let image = UIImage(data: data), error == nil else {
            print("图片加载失败:\(error?.localizedDescription ?? "未知错误")")
            return
        }
        // 存入缓存
        self.imageCache.setObject(image, forKey: fullURLString as NSString)
        // 更新UI
        DispatchQueue.main.async {
            self.imageView.image = image
        }
    }.resume()
}

总结

按照上面的方法修改后,图片会通过异步方式安全加载,并且在主线程更新UI,加上缓存的话不仅能稳定显示,还能提升App的性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:56:36