Swift 4中修改现有代码以从返回两个图片URL的API接口获取并解析两张图片
解决APOD API获取两张图片的问题
看起来你需要从NASA的APOD接口获取标准分辨率和高分辨率两张图片对吧?原来的代码只处理了单个url字段,我们需要调整几个关键部分来支持双图片的解析和下载:
关键修改步骤
1. 更新API响应模型
APOD API返回的JSON里包含url(标准图)和hdurl(高分辨率图)两个图片链接,首先要扩展你的响应结构体,同时考虑高分辨率图可能不存在的情况:
struct ApodApiResponse: Decodable { var url: String var hdurl: String? // 高分辨率图为可选字段 var title: String }
2. 修改响应结果枚举
原来的ApodImageResponse只能返回单张图,我们需要调整它来支持多图返回,同时兼容部分下载失败的场景:
enum ApodImageResponse { case Success(images: [UIImage], titles: [String]) // 存储多张图及对应标题 case PartialSuccess(mainImage: UIImage, title: String, errorMessage: String) // 仅单张成功 case Failure(errorMessage: String) // 全部失败 }
3. 重构并行下载逻辑
原来的代码是串行下载单张图,现在需要用DispatchGroup来并行处理两个图片下载任务,确保所有任务完成后再返回结果:
修改parseResponseAndGetImage方法:
static func parseResponseAndGetImage(data: Data?, urlResponse: URLResponse?, error: Error?, completion: ((ApodImageResponse) -> Void)?) { guard error == nil, let content = data else { completion?(.Failure(errorMessage: "获取API数据失败")) return } var apodApiResponse: ApodApiResponse do { apodApiResponse = try JSONDecoder().decode(ApodApiResponse.self, from: content) } catch { completion?(.Failure(errorMessage: "解析API响应失败:\(error.localizedDescription)")) return } // 整理需要下载的图片链接列表 var imageUrls: [String] = [apodApiResponse.url] if let hdUrl = apodApiResponse.hdurl { imageUrls.append(hdUrl) } let dispatchGroup = DispatchGroup() var downloadedImages: [UIImage] = [] var downloadErrors: [String] = [] for imageUrlString in imageUrls { guard let url = URL(string: imageUrlString) else { downloadErrors.append("无效图片链接:\(imageUrlString)") continue } dispatchGroup.enter() let urlRequest = URLRequest(url: url) URLSession.shared.dataTask(with: urlRequest) { data, _, error in defer { dispatchGroup.leave() } if let error = error { downloadErrors.append("下载图片失败:\(error.localizedDescription)") return } guard let imageData = data, let image = UIImage(data: imageData) else { downloadErrors.append("图片数据解析失败") return } downloadedImages.append(image) }.resume() } // 所有任务完成后统一返回结果 dispatchGroup.notify(queue: .main) { switch (downloadedImages.count, downloadErrors.count) { case (2, 0): completion?(.Success(images: downloadedImages, titles: [apodApiResponse.title, "\(apodApiResponse.title) (高清版)"])) case (1, _): completion?(.PartialSuccess(mainImage: downloadedImages[0], title: apodApiResponse.title, errorMessage: downloadErrors.joined(separator: " | "))) default: completion?(.Failure(errorMessage: downloadErrors.joined(separator: " | "))) } } }
4. 移除冗余方法
原来的parseImageFromResponse方法已经不需要了,图片解析逻辑已经整合到下载任务的闭包中。
完整修改后的代码
import Foundation import SwiftUI enum ApodImageResponse { case Success(images: [UIImage], titles: [String]) case PartialSuccess(mainImage: UIImage, title: String, errorMessage: String) case Failure(errorMessage: String) } struct ApodApiResponse: Decodable { var url: String var hdurl: String? var title: String } class ApodImageProvider { static func getImageFromApi(completion: ((ApodImageResponse) -> Void)?) { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" formatter.timeZone = TimeZone(abbreviation: "UTC") let date = Date() let urlString = "https://api.nasa.gov/planetary/apod?api_key=eaRYg7fgTemadUv1bQawGRqCWBgktMjolYwiRrHK&date=\(formatter.string(from: date))" guard let url = URL(string: urlString) else { completion?(.Failure(errorMessage: "无效API链接")) return } let urlRequest = URLRequest(url: url) let task = URLSession.shared.dataTask(with: urlRequest) { data, urlResponse, error in parseResponseAndGetImage(data: data, urlResponse: urlResponse, error: error, completion: completion) } task.resume() } static func parseResponseAndGetImage(data: Data?, urlResponse: URLResponse?, error: Error?, completion: ((ApodImageResponse) -> Void)?) { guard error == nil, let content = data else { completion?(.Failure(errorMessage: "获取API数据失败")) return } var apodApiResponse: ApodApiResponse do { apodApiResponse = try JSONDecoder().decode(ApodApiResponse.self, from: content) } catch { completion?(.Failure(errorMessage: "解析API响应失败:\(error.localizedDescription)")) return } var imageUrls: [String] = [apodApiResponse.url] if let hdUrl = apodApiResponse.hdurl { imageUrls.append(hdUrl) } let dispatchGroup = DispatchGroup() var downloadedImages: [UIImage] = [] var downloadErrors: [String] = [] for imageUrlString in imageUrls { guard let url = URL(string: imageUrlString) else { downloadErrors.append("无效图片链接:\(imageUrlString)") continue } dispatchGroup.enter() let urlRequest = URLRequest(url: url) URLSession.shared.dataTask(with: urlRequest) { data, _, error in defer { dispatchGroup.leave() } if let error = error { downloadErrors.append("下载\(imageUrlString)失败:\(error.localizedDescription)") return } guard let imageData = data, let image = UIImage(data: imageData) else { downloadErrors.append("\(imageUrlString)数据解析失败") return } downloadedImages.append(image) }.resume() } dispatchGroup.notify(queue: .main) { switch (downloadedImages.count, downloadErrors.count) { case (2, 0): completion?(.Success(images: downloadedImages, titles: [apodApiResponse.title, "\(apodApiResponse.title) (高清版)"])) case (1, _): completion?(.PartialSuccess(mainImage: downloadedImages[0], title: apodApiResponse.title, errorMessage: downloadErrors.joined(separator: " | "))) default: completion?(.Failure(errorMessage: downloadErrors.joined(separator: " | "))) } } } }
使用示例
调用时可以这样处理返回结果:
ApodImageProvider.getImageFromApi { response in switch response { case .Success(let images, let titles): print("成功获取\(images.count)张图片:\(titles)") // 可将图片展示在SwiftUI视图中,比如HStack里 case .PartialSuccess(let mainImage, let title, let error): print("获取主图成功:\(title),错误信息:\(error)") case .Failure(let error): print("获取图片失败:\(error)") } }
这样修改后,你的代码就能同时获取APOD的标准分辨率和高分辨率两张图片了~
内容的提问来源于stack exchange,提问作者astrakid932
相关产品推荐
相关产品推荐

