SwiftUI实现本地存储/缓存图片Image的功能
SwiftUI实现本地存储/缓存图片Image的功能

SwiftUI实现本地存储/缓存图片Image的功能

后台缓存

在SwiftUI中,如果不是本地Bundle中存储图片的话,在调用接口时,会获取到图片的URL链接,从而展示对应的图片。

例如,有一个接口提供加密的外币数据,接口中的image字段是加密外币图片的URL链接。

因此,需要获取到这个接口的数据,并考虑一个合适的存储方式保存加密外币的图片,以便在视图展示时,从iOS中直接获取加密外币的图片,而不是重新下载。

示例代码

let task = URLSession.shared.dataTask(with: apiURL) {data, response, error in
    // 检查是否有错误
    if let error = error {
        print("请求出错:\(error.localizedDescription)")
        return
    }
    let decoder = JSONDecoder() 
    // 检查响应数据
    if let data = data {
        do {
            let decoded = try decoder.decode([CryptoDTO].self, from: data)
            // 获取 Core Data 中的加密外币数据
            for coin in decoded {
                // 下载加密货币的图片
                self.DownloadCryptocurrencyImages(imageURL: coin.image, imageName: coin.symbol)
                // 创建 Core Data 对象的相关代码
            }
        } catch {
            print("解码报错: \(error)")
        }
    }
}
// 启动任务
task.resume()

在这段代码中,通过调用URLSession.shared.dataTask获取接口的数据,然后通过JSONDecoder将数据解码为数组对象。

遍历每一个数组对象,对象的image字段是URL格式,创建一个下载图片的方法,将图片的URL和图片的名称传递进去。

下载图片方法

let fileManager = FileManager.default
// 下载加密货币图片
func DownloadCryptocurrencyImages(imageURL: URL,imageName: String) {
    // 使用缓存目录(更适合长期存储)
    guard let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else {
        print("无法获取缓存目录")
        return
    }
    let localImageURL = cacheDirectory.appendingPathComponent("\(imageName).png")
    if fileManager.fileExists(atPath: localImageURL.path) {
        print("\(imageName)照片已存在,跳过下载")
        return
    } else {
        print("\(imageName)照片不存在,下载\(imageName)照片")
        let task = URLSession.shared.dataTask(with: imageURL) { data, response, error in
            if let error = error {
                print("下载失败:\(error.localizedDescription)")
                return
            }
            guard let data = data else {
                print("下载失败:无数据")
                return
            }
            do {
                // 将数据解析为字符串(例如 JSON)
                try data.write(to: localImageURL)
            } catch {
                print("预加载失败:\(error)")
            }
        }
        task.resume()   // 启动任务
    }
}

这个方法使用FileManager存储加密货币的图片。

首先在下载图片的方法中,定义了一个缓存目录的URL,存储加密货币的图片路径就是在这个缓存目录中追加了一个imageName.png,其中imageName就是传递进来的变量,也就意味着如果传递进来的图片名称是family,那么localImageURL就是family.png。

注意,imageName是传递进来的图片名称,是一个变量。

通过FileManager的fileExists方法检查图片路径是否存在,如果缓存目录中,有这样一个加密货币的图片,那么就return退出该方法。

如果缓存目录中没有这个图片,就调用URLSession.shared.dataTask方法,下载这个图片。下载完成后,使用try data.write(to:) 方法,将下载的Data数据写入到存储加密货币的图片路径上。

这样,就完成了后台的图片缓存的功能,图片会被下载到缓存目录中,图片的路径为缓存目录+文件名.png。

显示图片

在SwiftUI中,通过FileManager获取下载到本地的图片数据,然后转换成图片显示出来。

let fileManager = FileManager.default
if let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first {
    let localImageURL = cacheDirectory.appendingPathComponent("\(symbol).png")
    if let data = try? Data(contentsOf: localImageURL),let image = UIImage(data:data) {
        Image(uiImage: image)
            .resizable()
            .scaledToFill()
            .frame(width: 30, height: 30)
       
    } else {
        AsyncImage(url: imageUrl) { image in
            image
                .resizable()
                .scaledToFill()
                .frame(width: 30, height: 30)
        } placeholder: {
            ProgressView() // 显示加载占位符
                .onAppear {
                    // 该图片可能未实现缓存,尝试缓存该图片
                    DownloadCryptocurrencyImages(imageURL: imageUrl, imageName: symbol)
                }
        }
    }
}

首先,解包缓存文件夹的路径,设置图片路径(缓存文件夹的路径+图片名称.png)。

通过Data(contentsOf:)方法读取图片路径,如果读取成功,则表示缓存文件夹中,有这个加密货币的图片,返回图片的Data数据。

使用UIImage读取图片数据,如果图片的Data数据正常,那么就可以使用Image(uiImage:)显示图片。

如果UIImage读取的图片数据有问题,就不会显示出图片。

如果缓存文件夹中没有加密货币的图片,就需要使用AsyncImage加载远程图片,将加密货币的URL链接传递进行,就会从远程服务器上下载加密货币的图片。

这里还有一个细节就是,如果缓存文件夹中没有对应加密货币的图片,也就意味着在后台缓存时,可能没有缓存成功,比如下载图片的过程中中断导致的问题。这里就需要考虑重新调用一遍缓存图片的方法,以便后面可以从本地获取并显示图片,而不用访问服务器获取图片。

总结

本文主要讲述的是如果在后台缓存以及在视图文件中显示图片的方案。主要借助于FileManager的缓存目录,图片路径就是缓存目录+图片名称.png。

在后台缓存时,检查图片路径是否存在图片。如果存在图片,则表示之前已经缓存过图片,因此直接跳过。如果缓存文件夹中没有图片,那么就调用URLSession的请求方法,下载图片数据并存储在图片路径中。

在前台显示也是同样的逻辑,如果缓存目录中有图片,则解包并显示图片。如果没有图片,则使用AsyncImage加载图片URL并尝试重新缓存图片。

相关文章

1、SwiftUI加载和显示远程图片的AsyncImage:https://fangjunyu.com/2025/01/19/swiftui%e5%8a%a0%e8%bd%bd%e5%92%8c%e6%98%be%e7%a4%ba%e8%bf%9c%e7%a8%8b%e5%9b%be%e7%89%87%e7%9a%84asyncimage/

2、Swift显示图像的Image类:https://fangjunyu.com/2024/11/22/swift%e6%98%be%e7%a4%ba%e5%9b%be%e5%83%8f%e7%9a%84image%e7%b1%bb/

3、Swift UIImage和UIImageView类:https://fangjunyu.com/2024/11/02/swift-uiimage%e5%92%8cuiimageview%e7%b1%bb/

4、Swift 网络请求方法URLSession.shared.dataTask:https://fangjunyu.com/2024/10/31/swift-%e7%bd%91%e7%bb%9c%e8%af%b7%e6%b1%82%e6%96%b9%e6%b3%95urlsession-shared-datatask/

5、Swift处理和存储二进制数据的Data:https://fangjunyu.com/2024/11/21/swift%e5%a4%84%e7%90%86%e5%92%8c%e5%ad%98%e5%82%a8%e4%ba%8c%e8%bf%9b%e5%88%b6%e6%95%b0%e6%8d%ae%e7%9a%84data/

6、Swift 管理文件的FileManager类:https://fangjunyu.com/2024/11/03/swift-%e7%ae%a1%e7%90%86%e6%96%87%e4%bb%b6%e7%9a%84filemanager%e7%b1%bb/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注