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

如何解决URLSession加载图片时UIImageView(profilePic)的卡顿问题?

解决UIImageView加载图片卡顿问题

你的卡顿根源在于图片解码和渲染占用主线程,尤其是当图片尺寸大、分辨率高时,UIImage(data:)只是创建了对象,真正的解码操作会在图片首次显示时在主线程执行,直接阻塞UI刷新。另外当前代码没有缓存,重复加载同一图片还要重新下载,进一步加重卡顿。

给你几个针对性的解决办法:

1. 把图片解码移到后台线程执行

把解码操作放到后台,解码完成后再回主线程设置图片,避免阻塞UI:

private func addImage() {
    let donorId = donor.lastName
    guard let urlString = self.defaults.value(forKey: "url\(donorId)") as? String,
          let url = URL(string: urlString) else {
        return
    }
    let task = URLSession.shared.dataTask(with: url) { data, _, error in
        guard let data = data, error == nil else {
            self.donorsViewController.handle(error)
            return
        }
        
        // 后台线程处理解码
        DispatchQueue.global(qos: .userInitiated).async {
            guard let image = UIImage(data: data) else { return }
            // 强制触发解码:通过绘制图片完成解码
            UIGraphicsBeginImageContextWithOptions(image.size, false, UIScreen.main.scale)
            image.draw(at: .zero)
            let decodedImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            
            // 回到主线程设置图片
            DispatchQueue.main.async {
                self.profilePic.image = decodedImage
            }
        }
    }
    task.resume()
}

2. 加个本地缓存,避免重复下载

用NSCache实现图片缓存,同一图片只下载一次,提升加载速度:

// 类里加个静态缓存对象
private static let imageCache = NSCache<NSString, UIImage>()

private func addImage() {
    let donorId = donor.lastName
    guard let urlString = self.defaults.value(forKey: "url\(donorId)") as? String,
          let url = URL(string: urlString) else {
        return
    }
    let cacheKey = NSString(string: urlString)
    
    // 先查缓存,有直接用
    if let cachedImage = Self.imageCache.object(forKey: cacheKey) {
        DispatchQueue.main.async {
            self.profilePic.image = cachedImage
        }
        return
    }
    
    let task = URLSession.shared.dataTask(with: url) { data, _, error in
        guard let data = data, error == nil else {
            self.donorsViewController.handle(error)
            return
        }
        
        DispatchQueue.global(qos: .userInitiated).async {
            guard let image = UIImage(data: data) else { return }
            // 强制解码
            UIGraphicsBeginImageContextWithOptions(image.size, false, UIScreen.main.scale)
            image.draw(at: .zero)
            let decodedImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            
            // 存进缓存
            if let decodedImage = decodedImage {
                Self.imageCache.setObject(decodedImage, forKey: cacheKey)
            }
            
            DispatchQueue.main.async {
                self.profilePic.image = decodedImage
            }
        }
    }
    task.resume()
}

3. 缩放图片到ImageView的实际尺寸

如果原图比你的profilePic大很多,先把图片缩到和ImageView一样大,减少内存占用和渲染时间:

// 新增缩放方法
private func resizeImage(_ image: UIImage, to targetSize: CGSize) -> UIImage? {
    let size = image.size
    let widthRatio = targetSize.width / size.width
    let heightRatio = targetSize.height / size.height
    // 取最小比例,保证图片完整显示
    let scaleFactor = min(widthRatio, heightRatio)
    
    let newSize = CGSize(width: size.width * scaleFactor, height: size.height * scaleFactor)
    UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale)
    image.draw(in: CGRect(origin: .zero, size: newSize))
    let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return resizedImage
}

// 在addImage里替换解码部分的代码
DispatchQueue.global(qos: .userInitiated).async {
    guard let image = UIImage(data: data) else { return }
    // 缩放到profilePic的尺寸
    let targetSize = self.profilePic.bounds.size
    guard let resizedImage = self.resizeImage(image, to: targetSize) else { return }
    
    // 存缓存
    Self.imageCache.setObject(resizedImage, forKey: cacheKey)
    
    DispatchQueue.main.async {
        self.profilePic.image = resizedImage
    }
}

内容的提问来源于stack exchange,提问作者MartinG

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:07:44