移动端对大批量图片加载的优化方法(一)

移动端对大批量图片加载的优化方法(一)iOS

本篇主要从iOS开发中可以使用到的对大批量图片加载的优化方法进行整理。优化

1.异步加载

将图片加载任务放在后台线程中进行,避免阻塞主线程,这样可以保证应用的响应性和流畅性;

a.使用Operation和OperationQueue

NSOperation和NSOperationQueue是Apple提供的用于多线程处理的框架,可以为每个图片请求创建一个NSBlockOperation,然后添加到NSOperationQueue中;
优点:高度可定制,可以实现复杂的异步操作;
缺点:相对复杂,需要更多的代码和配置。

class AsyncImageLoader: NSObject {  
      
    static let shared = AsyncImageLoader()  
      
    private let operationQueue = OperationQueue()  
      
    func loadImages(withURLs imageURLs: [URL], completion: @escaping ([UIImage]) -> Void) {  
        if imageURLs.isEmpty {  
            completion([])  
            return  
        }  
          
        let operation = BlockOperation {  
            let loadedImages = self.loadImagesFromURLs(imageURLs)  
            completion(loadedImages)  
        }  
        operation.addDependency(BlockOperation { completion() })  
        operationQueue.addOperation(operation)  
    }  
      
    private func loadImagesFromURLs(_ imageURLs: [URL]) -> [UIImage] {  
        var loadedImages = [UIImage]()  
        var failedImages = [URL]()  
        for url in imageURLs {  
            let loadImageOperation = BlockOperation {  
                if let image = self.loadImage(from: url) {  
                    loadedImages.append(image)  
                } else {  
                    failedImages.append(url)  
                }  
            }  
            loadImageOperation.completionBlock = {  
                if failedImages.count > 0 {  
                    print("Failed to load images: \(failedImages)")  
                }  
            }  
            operationQueue.addOperation(loadImageOperation)  
        }  
        return loadedImages  
    }  
      
    private func loadImage(from url: URL) -> UIImage? {  
        // 在这里实现图片加载的逻辑,可以使用 URLSession 来异步加载数据,然后使用 UIImage 来解码图片。  
        return nil // 返回加载的图片,如果加载失败则返回 nil。  
    }  
}
b.使用GCD(Grand Central Dispatch)

GCD是Apple提供的一种在iOS和OS X上进行并发编程的解决方案,可以使用dispatch_async在后台线程加载图片;
优点:简单易用,性能良好;
缺点:对于更复杂的并发需求,可能需要更多的代码和配置。

class ImageLoader {  
      
    func loadImages(withURLs imageURLs: [URL], completion: @escaping ([UIImage]) -> Void) {  
        if imageURLs.isEmpty {  
            completion([])  
            return  
        }  
          
        let dispatchGroup = DispatchGroup()  
        var loadedImages = [UIImage]()  
        var failedImages = [URL]()  
          
        for url in imageURLs {  
            dispatchGroup.enter()  
              
            URLSession.shared.dataTask(with: url) { (data, response, error) in  
                if let error = error {  
                    failedImages.append(url)  
                    dispatchGroup.leave()  
                    return  
                }  
                  
                if let httpResponse = response as? HTTPURLResponse,  
                  httpResponse.statusCode != 200,  
                  let data = data {  
                    failedImages.append(url)  
                    dispatchGroup.leave()  
                    return  
                } else if let image = UIImage(data: data) {  
                    loadedImages.append(image)  
                } else {  
                    failedImages.append(url)  
                }  
                  
                dispatchGroup.leave()  
            }.resume()  
        }  
          
        dispatchGroup.notify(queue: .main) {  
            completion(loadedImages)  
            if failedImages.count > 0 {  
                print("Failed to load images: \(failedImages)")  
            }  
        }  
    }  
}
c.使用SDWebImage或Kingfisher等第三方库

这些库处理了异步加载和缓存等,可以非常简单的使用;
优点:简单易用,通常包含缓存机制和优化;
缺点:依赖于第三方库,可能不适合所有项目。

let url = URL(string: "https://example.com/image.jpg") // 替换为您的图片 URL  
let resource = ImageResource(downloadURL: url!)  
  
KingfisherManager.shared.retrieveImage(with: resource) { (image, error, cacheType, imageURL) in  
    if let image = image {  
        // 在这里处理加载完成的图片  
        imageView.image = image  
    } else if let error = error {  
        // 处理加载错误  
        print("Error: \(error.localizedDescription)")  
    }  
}

KingfisherManager.shared.cache.storeImage(image, forKey: "myKey", original: resource)

imageView.kf.setImage(with: resource) // 使用 Kingfisher 设置图片

KingfisherManager.shared.cache.clearMemoryCache() // 清空内存缓存  
KingfisherManager.shared.cache.clearDiskCache() // 清空磁盘缓存
d.使用Swift的并发特性

在Swift5.5引入,可以使用async/await来异步执行代码;
优点:语法简单,易于理解;
缺点:需要Swift5.5+版本。

func loadImage(from url: URL) async -> UIImage? {  
    let data: Data? = try? await Data.init(contentsOf: url)  
    if let data = data {  
        return UIImage(data: data)  
    }  
    return nil  
}  
  
// 使用示例  
let url = URL(string: "https://example.com/image.jpg") // 替换为实际的图片URL  
let image = await loadImage(from: url!)  
imageView.image = image

2.懒加载(Lazy Loading)

常用的优化技术,它只在需要显示图片时才开始加载,而不是一次性加载所有图片,可以减少内存占用和加载时间;

a.添加懒加载属性

为需要懒加载的图片设置一个属性;
使用didMoveToSuperview或didMoveToWindow方法来检查图片是否可见;
只有当图片显示时才开始加载图片。

b.使用第三方库

SDWebImage或Kingfisher已经内置了懒加载功能;
使用这些库可以简化懒加载实现过程。

imageView.kf.lazy(with: resource).placeholder(with: nil).into(imageView)

c.自定义ImageView

创建自定义的ImageVIew的子类,在layoutSubviews方法中检查图片是否可见,只有在图片即将显示时调用setImage方法。

d.ReactiveCocoa或RxSwift

使用响应式编程框架可以声明式方法处理懒加载,使用观察者模式来观察UI元素的状态,并在需要时触发图片加载。

e.避免一次性加载所有图片

即使使用了懒加载,一次性加载大量图片仍然可能导致内存问题,使用合适的缓存策略,并及时释放不再需要的资源。

f.预加载

在用户滚动视图时,预加载即将显示的图片,可以通过监听滚动事件并提前开始加载图片。

g.监控和调试

使用Xcode的Instruments工具来监控内存使用和性能瓶颈,调试和优化懒加载实现,确保它在各种情况下都能正常工作。

3.缓存机制

通过缓存,可以存储已加载的图片,以便需要时快速检索,而不是重新从网络或其他来源加载;

a.标准缓存策略

iOS提供了NSURLCache类,可以用于缓存HTTP请求和响应,可以通过配置NSURLCache的内存和磁盘容量以适应应用需求。

private func setupURLCache() {  
        // 创建一个自定义的URL缓存对象  
        let cache = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: "myCustomCachePath")  
        URLCache.shared = cache  
    }  
  
private func loadImages() {  
        // 模拟加载大量图片  
        for i in 1...100 {  
            let url = URL(string: "https://example.com/image_\(i).jpg")!  
            let request = URLRequest(url: url)  
            URLSession.shared.dataTask(with: request) { (data, response, error) in  
                if let error = error {  
                    print("Error loading image: \(error.localizedDescription)")  
                    return  
                }  
                if let response = response as? HTTPURLResponse, let data = data {  
                    // 将响应数据缓存到磁盘中  
                    URLCache.shared.storeCachedResponse(response, for: request)  
                }  
            }.resume()  
        }  
    }  
b.自定义缓存策略

对于更复杂的用例,可以实现自己的缓存策略;
考虑使用键值存储(如UserDefaults或CoreData)或第三方缓存库(Haneke或Flare)。

// 配置Flare  
    Flare.shared.config = .init(diskCacheDirectory: "flare_cache", diskCacheSizeLimit: 100 * 1024 * 1024) // 100MB  
    
    // 使用Flare加载图片并缓存  
Flare.shared.load(imageURL: imageURL) { (result) in  
    switch result {  
    case .success(let image):  
        imageView.image = image  
    case .failure(let error):  
        print("加载图片失败: \(error.localizedDescription)")  
    }  
}

Flare.shared.clearDiskCache() // 清理磁盘缓存

c.压缩和优化

将图片存储到缓存之前,对其进行适当压缩和优化,可以减少缓存的大小并提高加载速度。

func compressImage(_ image: UIImage, quality: CGFloat = 0.8) -> Data? {  
    var compressedData: Data?  
    let imageRef: CGImage = image.cgImage?.cropping(to: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))  
    if let imageRep = CGImageRepresentation(imageRef) {  
        compressedData = imageRep.jpegData(options: [.compressionFactor: quality])  
    }  
    return compressedData  
}  
d.定期清理缓存

定期清理过是或不常用的缓存数据以释放空间并保持缓存的有效性;
可以使用定时任务或后台任务来执行清理操作。

f.监听网络和响应时间

监听设备的网络状态变化,并根据网络条件动态调整图片加载策略;
监测服务器响应时间,以便在必要时进行重试或回退到缓存数据。

g.离线优先

在用户离线时提供预先加载和缓存的图片,使用后台任务和后台刷新来预先获取数据。

4.优化图片质量

加载图片时,可以根据需要调整图片的质量(可以通过降低分辨率或压缩图片来减少加载时间和内存占用)。

// 创建一个UIImage对象,并使用缩略图模式加载图片  
let image = UIImage(named: "example.jpg")?.generateThumbnail(width: 100)  
  
// 将缩略图设置到UIImageView中  
let imageView = UIImageView(image: image)

5.使用适当的图片格式

选择适当的图片格式对于优化图片加载性能和节省存储空间很重要;

a.JPEG(Joint Photographic Experts Group)

特点:广泛使用的格式,支持有损压缩;
适用场景:照片和其他需要高质量细节的图像。

b.PNG(Portable Network Graphics)

特点:无损压缩,支持透明度和alpha通道;
适用场景:图标、按钮和其他需要透明背景的图像。

c.GIF(Graphics Interchange Format)

特点:支持动画和透明度;
适用场景:动画和循环显示的简单图形。

d.TIFF(Tagged Image File Format)

特点:支持多种压缩算法和颜色模式;
适用场景:需要高质量和多页的文档或图像。

e.WebP(Web Picture)

特点:由Google开发的现代格式,支持有损和无损压缩;
适用场景:需要在网页上快速加载的图片,以及需要节省带宽和存储的应用。

f.HEIF(High Efficiency Image File Format)

特点:高效压缩,支持高分辨率和透明度;
适用场景:iPhone和iPad上的照片,以及其他需要搞笑存储和传输的图像。

g.APNG(Animated Portable Network Graphics)

特点:类似于GIF的动画格式,但支持更高的图像质量和更小的文件大小;
适用场景:需要展示动画效果的网页和其他应用程序。

h.SVG(Scalable Vector Graphics)

特点:基于矢量的格式,可缩放而不失清晰度;
适用场景:需要高分辨率和适应不同屏幕尺寸的图形设计。

i.PDF(Portable Document Format)

支持矢量图形和高质量打印输出,适用于电子文档、表单和需要精确布局的图像。

j.RAW

高质量的原始图像格式,通常用于专业摄影和需要无损质量的场合;
适用场景:需要最大程度保留原始图像数据的情境。

k.Apple ProRAW

Apple专有的原始图像格式,结合了RAW和JPEFG的优势,适用于iPhone和iPad上的专业摄影;
适用场景:需要高质量、灵活且易于分享的摄影作品。

6.组织图片资源

将图片资源合理组织起来,以方便管理和查找,提高加载效率;

a.适当的目录结构

将图片资源按功能或用途分类,放在不同的文件夹中。

b.合适的文件命名约定

为图片文件使用描述性的、易于理解的名称,避免使用随机或过于复杂的文件名。

c.利用资产库(Asset Catalog)
d.使用适当的请求头和响应头

根据服务器的设置,通过设置请求头和响应头来优化图像的加载和缓存(Cache-Control、ETag)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/304124.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频剪辑方法:智能转码从视频到图片序列,高效转换攻略

在视频编辑和后期处理中,经常要将视频转换为图片序列,以便进行单独编辑或应用。下面一起来看云炫AI智剪如何批量智能转码的方法,高效地将视频转换为图片序列。 视频转为序列图片缩略图效果 视频转为序列图片的效果图,画面清晰&a…

vue3 img图片怎么渲染

在 Vue3 中加载图片&#xff08;img&#xff09;src地址时&#xff0c;出现无法加载问题。网上很多都建议使用 require 加载相对路径&#xff0c;如下&#xff1a; <img :src"require(../assets/img/icon.jpg)"/>但是按照这种方式加载又会报错如下&#xff1a;…

Access、Trunk、Hybrid接口接收发送数据帧标签剥离区分

以太网二层接口类型 Access Trunk Hybrid 总结&#xff1a; VLAN原理最全最详细讲解&#xff01;彻底搞懂VLAN打和摘tag过程

亚马逊鲲鹏自动测评系统:提升店铺流量与销售的利器

在跨境电商领域&#xff0c;提升店铺流量、排名以及销售业绩一直是卖家们关注的焦点。近期&#xff0c;亚马逊鲲鹏自动测评系统的推出备受关注&#xff0c;成为卖家们提升竞争力的得力工具。据真实客户反馈&#xff0c;该系统不仅能够全自动化批量操作&#xff0c;而且内置了防…

.NET学习教程一——.net基础定义+VS常用设置

一、定义 .NET分为.NET平台和.NET框架。 .NET平台&#xff08;厨房&#xff09;.NET FrameWork 框架&#xff08;柴米油盐酱醋茶&#xff09; .NET平台&#xff08;中国移动联通平台&#xff09;.NET FrameWork 框架&#xff08;信号塔&#xff09; .NET平台基于.NET Fra…

记一次JSF异步调用引起的接口可用率降低

前言 本文记录了由于JSF异步调用超时引起的接口可用率降低问题的排查过程&#xff0c;主要介绍了排查思路和JSF异步调用的流程&#xff0c;希望可以帮助大家了解JSF的异步调用原理以及提供一些问题排查思路。本文分析的JSF源码是基于JSF 1,7.5-HOTFIX-T6版本。 起因 问题背景…

含中间直流的三相电力电子变压器PET仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 背景&#xff1a; 目前高压电网中应用的绝大多数电力变压器都属于传 统电力变压器&#xff0c;传统变压器的优势在于工艺简单、安全性 较强。但传统变压器本身的弊端也非常突出&#xff0c;占地大、重 量大&…

0108作业

#include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {this->setWindowTitle("腾讯会议");this->resize(470,800);//设置界面大小this->setFixedSize(470,800);//锁定界面大小this->setStyleSheet("background-color:w…

FPGA状态机学习

Verilog 是硬件描述语言&#xff0c;硬件电路是并行执行的&#xff0c;当需要按照流程或者步骤来完成某个功能时&#xff0c;代码中通常会使用很多个 if 嵌套语句来实现&#xff0c;这样就增加了代码的复杂度&#xff0c;以及降低了代码的可读性&#xff0c;这个时候就可以使用…

办公文档,私人专用

一、安装Minio 1.1、创建文件夹&#xff0c;并在指定文件夹中下载minio文件 cd /opt mkdir minio cd minio touch minio.log wget https://dl.minio.io/server/minio/release/linux-amd64/minio1.2、赋予minio文件执行权限 chmod 777 minio1.3、启动minio ./minio server /…

利用矩阵特征值解决微分方程【1】

目录 一. 特征值介绍 二. 单变量常微分方程 三. 利用矩阵解决微分方程问题 四. 小结 4.1 矩阵论 4.2 特征值与特征向量内涵 4.3 应用 一. 特征值介绍 线性代数有两大基础问题&#xff1a; 如果A为对角阵的话&#xff0c;那么问题就很好解决。需要注意的是&#xff0c;矩…

14.网络编程入门和网络应用开发

网络编程入门 计算机网络基础 计算机网络是独立自主的计算机互联而成的系统的总称&#xff0c;组建计算机网络最主要的目的是实现多台计算机之间的通信和资源共享。今天计算机网络中的设备和计算机网络的用户已经多得不可计数&#xff0c;而计算机网络也可以称得上是一个“复…

媒介pr工作内容有哪些,小红书达人投放总结!

随着新媒体技术的发展&#xff0c;很多人都不约而同的选择成为一名新媒体从业人员&#xff0c;这其中就包括媒介PR。当涉及媒介投放技巧时&#xff0c;我们需要思考许多关键因素&#xff0c;使我们的公关活动取得理想结果。今天我们就来分享一下媒介pr工作内容有哪些&#xff0…

CTF-PWN-沙箱逃脱-【seccomp和prtcl-2】

文章目录 沙箱逃脱prtcl题HITCON CTF 2017 Quals Impeccable Artifactflag文件对应prctl函数检查源码思路exp 沙箱逃脱prtcl题 HITCON CTF 2017 Quals Impeccable Artifact flag文件 此时的flag文件在本文件夹建一个即可 此时的我设置的flag为 对应prctl函数 第一条是禁止…

答疑解惑:核技术利用辐射安全与防护考核

前言 最近通过了《核技术利用辐射安全与防护考核》&#xff0c;顺利拿到了合格证。这是从事与辐射相关行业所需要的一个基本证书&#xff0c;考试并不难&#xff0c;在此写篇博客记录一下主要的知识点。 需要这个证书的行业常见的有医疗方面的&#xff0c;如放疗&#xff0c;…

Python实战化采集淘宝1688京东详情,API接口开发系列

Python实战化采集淘宝、京东详情和API接口开发是一个涉及多个步骤和技术的过程。下面是一个简化的教程&#xff0c;帮助你开始这个过程。 1. 准备工作 首先&#xff0c;确保你已经安装了Python&#xff0c;并且了解基本的Python编程。此外&#xff0c;你可能需要安装一些库&a…

php 的数据类型

目录 1.整型 2.浮点型 3.布尔类型 4.字符串 5.数组 6.NULL 7.对象 8.资源类型 查看变量对应值的类型&#xff1a; 1.使用“gettype(传入一个变量var)”来显示变量var的类型; 只会显示类型 2.使用“var_dump(传入一个变量var)”来显示变量var的类型; 会显示具体内容打…

精进单元测试技能——Pytest断言的艺术

本篇文章主要是阐述Pytest在断言方面的应用。让大家能够了解和掌握Pytest针对断言设计了多种功能以适应在不同测试场景上使用。 了解断言的基础 在Pytest中&#xff0c;断言是通过 assert 语句来实现的。简单的断言通常用于验证预期值和实际值是否相等&#xff0c;例如&#xf…

一、MOJO环境部署和安装

以Ubuntu系统为例。 安装mojo-CLI curl https://get.modular.com | MODULAR_AUTHmut_fe303dc5ca504bc4867a1db20d897fd8 sh - 安装mojo SDK modular auth mojo modular auth install mojo 查看mojo版本号 mojo --version 输入mojo指令&#xff0c;进入交互编程窗口
最新文章