使用Kingfisher获取网络图片后存入数组复用的实现求助
没问题,我帮你调整代码实现预加载图片到数组再轮播的需求,这样就能彻底避免重复网络请求了。下面是具体的实现思路和代码示例:
实现思路
- 先定义存储图片的数组、当前展示索引和定时器变量
- 批量预加载所有目标图片URL对应的
UIImage,存入数组(用Kingfisher的ImageDownloader来获取图片数据) - 所有图片加载完成后,启动定时器,每隔5秒从数组中取对应图片展示到ImageView
- 处理边界情况(比如数组为空、索引越界、下载失败的图片)
完整代码示例
import UIKit import Kingfisher class ImageCarouselVC: UIViewController { // 你的展示ImageView @IBOutlet weak var displayImageView: UIImageView! // 存储预加载好的图片 private var preloadedImages: [UIImage] = [] // 当前展示的图片索引 private var currentImageIndex = 0 // 轮播定时器 private var carouselTimer: Timer? // 替换成你的所有目标图片URL数组 private let imageURLs: [URL] = [ URL(string: "https://example.com/image1.jpg")!, URL(string: "https://example.com/image2.jpg")!, URL(string: "https://example.com/image3.jpg")! ] override func viewDidLoad() { super.viewDidLoad() // 启动图片预加载流程 preloadAllImages() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 页面消失时销毁定时器,避免内存泄漏 carouselTimer?.invalidate() carouselTimer = nil } private func preloadAllImages() { let dispatchGroup = DispatchGroup() for url in imageURLs { dispatchGroup.enter() // 使用Kingfisher的ImageDownloader下载图片,拿到UIImage对象 ImageDownloader.shared.downloadImage(with: url) { [weak self] result in defer { dispatchGroup.leave() } switch result { case .success(let value): // 下载成功,将图片加入数组(确保在主线程更新UI相关数组) DispatchQueue.main.async { self?.preloadedImages.append(value.image) } case .failure(let error): // 处理下载失败的情况,比如添加占位图或者跳过 print("下载图片失败: \(error.localizedDescription)") DispatchQueue.main.async { self?.preloadedImages.append(UIImage(named: "placeholder")!) } } } } // 所有图片下载完成后启动轮播 dispatchGroup.notify(queue: .main) { [weak self] in guard let self = self, !self.preloadedImages.isEmpty else { print("没有可用图片,无法启动轮播") return } // 先展示第一张图片 self.displayImageView.image = self.preloadedImages[self.currentImageIndex] // 启动定时器,每5秒切换一次 self.startCarouselTimer() } } private func startCarouselTimer() { carouselTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in guard let self = self else { return } // 更新索引,取模运算避免越界 self.currentImageIndex = (self.currentImageIndex + 1) % self.preloadedImages.count // 从数组取图片直接展示 self.displayImageView.image = self.preloadedImages[self.currentImageIndex] } } }
关键细节说明
- 预加载方式:用
ImageDownloader.shared.downloadImage而不是直接用kf.setImage,因为我们需要拿到UIImage对象存入数组,而不是直接设置到ImageView - 异步处理:用
DispatchGroup来等待所有图片下载完成,确保轮播开始时数组已经有内容 - 线程安全:所有更新UI和数组的操作都放在主线程,避免多线程冲突
- 内存管理:在
viewWillDisappear中销毁定时器,并用weak self避免循环引用 - 边界处理:检查数组是否为空,用取模运算处理索引越界,同时处理下载失败的情况(比如添加占位图)
内容的提问来源于stack exchange,提问作者user7477041




