URLImage
URLImage
是一个 SwiftUI 视图,用于显示从提供的 URL 下载的图像。 URLImage
为您管理来自远程位置的图像下载并本地缓存,包括内存和网络磁盘缓存。
使用 URLImage
非常简单
URLImage(url: url) { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
}
查看 演示应用 中的示例。
目录
特性
- SwiftUI 的远程图像视图;
- 本地图像缓存;
- 完全可定制,包括占位符、进度指示、错误和处理图像视图;
- 控制多个下载方面以获得更好的性能。
安装
URLImage
可以使用 Swift Package Manager 或 CocoaPods 进行安装。
使用 Swift 包管理器
使用包 URL 搜索 URLImage
包:[https://github.com/dmytro-anokhin/url-image](https://github.com/dmytro-anokhin/url-image)。
有关如何集成包依赖项,请参阅 将包依赖项添加到您的应用程序 文档。
使用 Cocoa Pods
将 URLImage
添加到您的 Podfile。
pod 'URLImage'
有关为项目设置 Cocoa Pods 的信息,请参阅 [https://cocoapods.org.cn](https://cocoapods.org.cn)。
使用
基础知识
URLImage
预期图像的 URL 和内容视图
import URLImage // Import the package module
URLImage(url: url,
content: { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
})
状态
URLImage
在 4 个状态之间进行转换
- 空状态,表示尚未开始下载或没有内容可显示;
- 进行中的状态,用于指示下载过程;
- 失败状态,如果发生错误;
- 内容,用于显示图像。
每种状态都有一个单独的视图,可以使用闭包提供。您还可以使用 URLImageOptions
来自定义某些设置,例如缓存策略和过期间隔。
struct MyView: View {
let url: URL
let id: UUID
init(url: URL, id: UUID) {
self.url = url
self.id = id
formatter = NumberFormatter()
formatter.numberStyle = .percent
}
private let formatter: NumberFormatter // Used to format download progress as percentage. Note: this is only for example, better use shared formatter to avoid creating it for every view.
var body: some View {
URLImage(url: url,
options: URLImageOptions(
identifier: id.uuidString, // Custom identifier
expireAfter: 300.0, // Expire after 5 minutes
cachePolicy: .returnCacheElseLoad(cacheDelay: nil, downloadDelay: 0.25) // Return cached image or download after delay
),
empty: {
Text("Nothing here") // This view is displayed before download starts
},
inProgress: { progress -> Text in // Display progress
if let progress = progress {
return Text(formatter.string(from: progress as NSNumber) ?? "Loading...")
}
else {
return Text("Loading...")
}
},
failure: { error, retry in // Display error and retry button
VStack {
Text(error.localizedDescription)
Button("Retry", action: retry)
}
},
content: { image in // Content view
image
.resizable()
.aspectRatio(contentMode: .fit)
})
}
}
图片信息
如果您需要获取图片信息,例如大小,或访问下层的 CGImage
对象,可以使用 init(url: URL, content: @escaping (_ image: Image, _ info: ImageInfo) -> Content)
初始化器。
缓存
URLImage
使用了两个缓存
- 内存缓存,用于快速访问;
- 本地磁盘缓存。
下载的图片存储在用户缓存文件夹中。这允许操作系统负责清理文件。定期手动清理也是一个好主意。
您可以通过在启动过程中调用 cleanup
来删除已过期的图片。如果您使用过之前的 URLImage
版本,它还将删除图片文件。
URLImageService.shared.cleanup()
下载的图片经过一段时间后就会过期。过期的图片会在 cleanup
程序中删除。过期间隔可以使用 URLImageOptions
的 expiryInterval
属性来设置。
您还可以使用 URLImageService
删除单个或所有缓存的图片。
使用 URLCache
或者,您可以使用 URLCache
。您可以全局配置包,也可以按视图配置。
URLImageService.shared.defaultOptions.cachePolicy = .useProtocol
// Download using `URLSessionDataTask`
URLImageService.shared.defaultOptions.loadOptions.formUnion(.inMemory)
// Set your `NSURLRequest.CachePolicy`
URLImageService.shared.defaultOptions.urlRequestConfiguration.cachePolicy = .returnCacheDataElseLoad
使用 URLCache
添加了对 Cache-Control 头的支持。作为权衡,您会失去一些控制,例如内存缓存、下载延迟、过期间隔(您可以通过Cache-Control 头获得)。它也只适用于内存下载(使用 URLSessionDataTask
)。
选项
URLImage
允许您通过 URLImageOptions
结构控制下载和缓存的各个方面。您可以使用 URLImageService.shared.defaultOptions
属性设置默认选项。以下是主要设置:
identifier: String?
默认情况下,图片通过其 URL 识别。作为替代,您还可以提供一个字符串标识符来覆盖此设置。
expiryInterval: TimeInterval?
缓存图片在此时间间隔后过期,并可被删除。图片会作为在 缓存 段落中描述的清理程序的一部分被删除。
maxPixelSize: CGSize?
解码图像的最大像素尺寸。如果没有指定此属性,则解码图像的宽度和高度不受限制,可能与图像本身一样大。
cachePolicy: CachePolicy
缓存策略控制从缓存中加载图像的方式。
缓存策略
缓存策略,类型为 URLImageOptions.CachePolicy
,允许指定 URLImage
如何利用缓存,类似于 NSURLRequest.CachePolicy
。此类型还可以指定访问磁盘缓存和开始下载的延迟。
returnCacheElseLoad
从缓存返回图像或下载它。
returnCacheDontLoad
从缓存返回图像,不下载它。
ignoreCache
忽略缓存图像并下载远程图像。
一些选项可以使用 URLImageService.shared.defaultOptions
属性全局设置。下列选项是默认设置的
- `expireAfter` 为 24 小时;
- `cachePolicy` 为 `returnCacheElseLoad`,且无延迟;
- `maxPixelSize` 为 1000 x 1000 像素(watchOS 为 300 x 300 像素)。
获取图像
您可能希望在没有任何视图的情况下下载图像。这可以通过使用 RemoteImagePublisher
对象来实现。`RemoteImagePublisher` 可以缓存图像供 `URLImage` 视图未来使用。
下载图像为 CGImage
并忽略任何错误
cancellable = URLImageService.shared.remoteImagePublisher(url)
.tryMap { $0.cgImage }
.catch { _ in
Just(nil)
}
.sink { image in
// image is CGImage or nil
}
作为 [CGImage?]
数组下载多个图像
let publishers = urls.map { URLImageService.shared.remoteImagePublisher($0) }
cancellable = Publishers.MergeMany(publishers)
.tryMap { $0.cgImage }
.catch { _ in
Just(nil)
}
.collect()
.sink { images in
// images is [CGImage?]
}
当使用 `RemoteImagePublisher` 对象下载图像时,所有选项都适用,就像为 `URLImage` 对象那样。默认情况下,下载的图像将在磁盘上缓存。这可以加快在应用后期显示图像的速度。此外,这目前是 iOS 14 小部件中显示图像的唯一支持方式。
在 iOS 14 小部件中下载图像
不幸的是,WidgetKit 中的视图无法运行异步操作:[Apple 开发者论坛](https://developer.apple.com/forums/thread/652581)。建议的方式是在 TimelineProvider
中加载数据,包括图像。
您仍然可以使用 URLImage
来做这件事。想法是在 TimelineProvider
中使用 RemoteImagePublisher
对象加载图像,并在 URLImage
视图中显示它。
报告一个虫子
使用GitHub issue来报告虫子。当可能时,请包含以下信息。
总结和/或背景;操作系统和您使用的设备;URLImage库的版本;您期望发生的事情;实际发生的事情;其他信息:展示bug的截图或视频;崩溃日志;示例代码,请尝试在无依赖项的情况下编译;测试数据:如果您使用公共资源,请提供图片的URL。
请确保有一个可复现的场景。理想情况下,请提供示例代码。如果您提交了示例代码,请确保它能够编译 ;)
请求新特性
使用GitHub issues来请求新特性。
贡献
欢迎贡献。在提交拉取请求之前,请先创建GitHub issue以规划并讨论实现。