Swift天气应用中如何正确稳定显示天气图标?
解决Swift天气App图标不稳定显示的问题
嘿,我仔细看了你的问题和代码片段,图标偶尔显示不稳定的情况,主要问题出在图片加载的异步处理方式以及UI更新的线程使用上,咱们一步步来修复:
问题分析
- 你用了全局变量
image来存储图片对象,这种方式很容易在多线程场景下出现赋值不及时或者被覆盖的情况,导致UI更新时拿到的图片可能是空的或者旧的。 - 使用
DispatchQueue.main.sync来更新UI是非常危险的——如果当前代码已经运行在主线程,调用sync会直接造成死锁,阻塞UI刷新,这也是图标偶尔不显示的重要原因。 - 接口返回的图标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
相关产品推荐
相关产品推荐

