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

无法通过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的错误日志其实不是导致图片不显示的原因,只是系统的警告,真正的问题出在图片加载逻辑上。

修正方案

正确的流程应该是:

  1. 调用dog.ceo API获取图片的URL字符串
  2. 将该字符串转为URL对象,再发起网络请求加载图片的二进制数据
  3. 将二进制数据转为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:09:24