无法通过API加载随机图片问题求助(iOS URLSession实现)
如何通过dog.ceo API正确加载随机狗狗图片?
我是API加载的新手,正在尝试通过URLSession实现随机狗狗图片加载,使用的API接口返回随机狗狗图片的URL。以下是我的实现代码:
import UIKit class ViewController: UIViewController { @IBOutlet weak var imageOfDog: UIImageView! struct dataForLoading: Codable { let message: String } override func viewDidLoad() { super.viewDidLoad() // 加载URL let url = "https://dog.ceo/api/breeds/image/random" guard let loadUrl = URL(string: url) else { return } // 使用URL发起URLSession请求 URLSession.shared.dataTask(with: loadUrl) {(data, response, error) in if error != nil{ print("请求出错:") print(error!.localizedDescription) } // 解码JSON guard let data = data else { return } do { let jsonData = try JSONDecoder().decode(dataForLoading.self, from: data) DispatchQueue.main.async { self.imageOfDog.image = UIImage(named: jsonData.message) } } catch let jsonError { print(jsonError) } }.resume() } }
运行项目时出现如下错误:
Random dog image[5960:196973] [framework] CUIThemeStore: No theme registered with id=0
我认为自己的解码操作存在问题,想请教如何通过该API正确加载图片。该API返回的数据格式如下:
{"message":"https://images.dog.ceo/breeds/elkhound-norwegian/n02091467_5985.jpg","status":"success"}
我的思路是先获取API返回的图片URL,再将其传入UIImageView显示图片。
问题分析
你遇到的核心问题不是解码错误,而是加载图片的方式错了:UIImage(named:)方法是用来加载APP本地资源包中的图片的,而你传入的是网络图片的URL字符串,这显然无法正确加载图片。那个CUIThemeStore的错误日志其实不是导致图片不显示的原因,只是系统的警告,真正的问题出在图片加载逻辑上。
修正方案
正确的流程应该是:
- 调用dog.ceo API获取图片的URL字符串
- 将该字符串转为
URL对象,再发起网络请求加载图片的二进制数据 - 将二进制数据转为
UIImage,最后在主线程更新UIImageView
下面是修正后的完整代码:
import UIKit class ViewController: UIViewController { @IBOutlet weak var imageOfDog: UIImageView! // 规范Codable结构体命名(首字母大写,语义化) struct DogImageResponse: Codable { let message: String let status: String // 可以加上API返回的status字段,方便校验请求状态 } override func viewDidLoad() { super.viewDidLoad() loadRandomDogImage() } // 封装加载逻辑,代码更清晰 private func loadRandomDogImage() { guard let apiUrl = URL(string: "https://dog.ceo/api/breeds/image/random") else { print("无效的API URL") return } URLSession.shared.dataTask(with: apiUrl) { [weak self] data, response, error in // 处理请求错误 if let error = error { print("API请求失败:\(error.localizedDescription)") return } // 校验响应状态码(可选,但推荐) guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print("响应状态异常") return } // 解码JSON数据 guard let data = data else { print("未获取到API返回数据") return } do { let dogResponse = try JSONDecoder().decode(DogImageResponse.self, from: data) // 校验是否成功获取图片URL guard let imageUrl = URL(string: dogResponse.message) else { print("无效的图片URL") return } // 加载图片数据 self?.loadImage(from: imageUrl) } catch { print("JSON解码失败:\(error.localizedDescription)") } }.resume() } // 单独封装图片加载方法 private func loadImage(from url: URL) { URLSession.shared.dataTask(with: url) { [weak self] data, _, error in if let error = error { print("图片加载失败:\(error.localizedDescription)") return } guard let imageData = data, let dogImage = UIImage(data: imageData) else { print("无法将数据转为UIImage") return } // 必须在主线程更新UI DispatchQueue.main.async { self?.imageOfDog.image = dogImage } }.resume() } }
关键优化点
- 语义化命名:把
dataForLoading改为DogImageResponse,更清晰表达结构体用途,同时加上status字段,便于校验API请求是否成功 - 代码拆分:将API请求和图片加载拆分为两个方法,代码结构更清晰,也方便复用
- 错误处理增强:增加了URL有效性校验、HTTP状态码校验、图片数据有效性校验,便于排查问题
- 弱引用self:在闭包中使用
[weak self]避免循环引用 - 正确的图片加载方式:通过
URLSession加载网络图片数据,再转为UIImage
补充说明
那个CUIThemeStore: No theme registered with id=0的警告通常是Xcode的系统日志,不会影响功能实现,你可以忽略它。
内容的提问来源于stack exchange,提问作者heli bhadeshiya
相关产品推荐
相关产品推荐

