我是 SwiftUI 新手,正在研究如何从 URL 下载图像。我发现在 iOS15 中你可以使用 AsyncImage 来处理图像的所有阶段。代码如下所示。
AsyncImage(url: URL(string: urlString)) { phase in
switch phase {
case .success(let image):
image
.someModifers
case .empty:
Image(systemName: "Placeholder Image")
.someModifers
case .failure(_):
Image(systemName: "Error Image")
.someModifers
@unknown default:
Image(systemName: "Placeholder Image")
.someModifers
}
}
Run Code Online (Sandbox Code Playgroud)
我会启动我的应用程序,每次我在列表上上下滚动时,它都会再次下载图像。那么我怎样才能添加缓存呢?我试图像在 Swift 中那样添加缓存。像这样的东西。
struct DummyStruct {
var imageCache = NSCache<NSString, UIImage>()
func downloadImageFromURLString(_ urlString: String) {
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
if let _ = error {
fatalError()
}
guard let data = data, let image = UIImage(data: data) else { return }
imageCache.setObject(image, forKey: NSString(string: urlString))
}
.resume()
}
}
Run Code Online (Sandbox Code Playgroud)
但事情并没有那么顺利。所以我想知道有没有办法为 AsyncImage 添加缓存?感谢您的帮助。
Lor*_*ngo 66
我和你有同样的问题。CachedAsyncImage我通过编写一个与 保持相同 API 的解决方案AsyncImage,以便它们可以轻松互换,同时考虑到未来的本机缓存支持AsyncImage.
我做了一个Swift 包来分享它。
CachedAsyncImage具有与 完全相同的 API 和行为AsyncImage,因此您只需更改此设置:
AsyncImage(url: logoURL)
Run Code Online (Sandbox Code Playgroud)
对此:
CachedAsyncImage(url: logoURL)
Run Code Online (Sandbox Code Playgroud)
除了AsyncImage初始化器之外,您还可以指定要使用的缓存(默认情况下URLCache.shared使用):
CachedAsyncImage(url: logoURL, urlCache: .imageCache)
Run Code Online (Sandbox Code Playgroud)
// URLCache+imageCache.swift
extension URLCache {
static let imageCache = URLCache(memoryCapacity: 512*1000*1000, diskCapacity: 10*1000*1000*1000)
}
Run Code Online (Sandbox Code Playgroud)
请记住,设置缓存时,响应(在本例中是我们的图像)不得大于磁盘缓存的 5% 左右(请参阅此讨论)。
这是回购协议。
Rya*_*ung 13
希望这可以帮助其他人。我发现了这个很棒的视频,其中讨论了使用下面的代码来构建供您自己使用的异步图像缓存功能。
import SwiftUI
struct CacheAsyncImage<Content>: View where Content: View{
private let url: URL
private let scale: CGFloat
private let transaction: Transaction
private let content: (AsyncImagePhase) -> Content
init(
url: URL,
scale: CGFloat = 1.0,
transaction: Transaction = Transaction(),
@ViewBuilder content: @escaping (AsyncImagePhase) -> Content
){
self.url = url
self.scale = scale
self.transaction = transaction
self.content = content
}
var body: some View{
if let cached = ImageCache[url]{
let _ = print("cached: \(url.absoluteString)")
content(.success(cached))
}else{
let _ = print("request: \(url.absoluteString)")
AsyncImage(
url: url,
scale: scale,
transaction: transaction
){phase in
cacheAndRender(phase: phase)
}
}
}
func cacheAndRender(phase: AsyncImagePhase) -> some View{
if case .success (let image) = phase {
ImageCache[url] = image
}
return content(phase)
}
}
fileprivate class ImageCache{
static private var cache: [URL: Image] = [:]
static subscript(url: URL) -> Image?{
get{
ImageCache.cache[url]
}
set{
ImageCache.cache[url] = newValue
}
}
}
Run Code Online (Sandbox Code Playgroud)
val*_*ine 10
也许稍后会参加聚会,但我遇到了这个确切的问题,即 AsyncImage 与 ScrollView / LazyVStack 布局结合使用时性能不佳。
根据此帖子,该问题似乎在某种程度上是由于苹果当前的实施造成的,并且在未来的某个时候它将得到解决。
我认为我们可以使用的最面向未来的方法类似于Ryan Fung 的响应,但不幸的是,它使用旧语法并且错过了重载的 init(带或不带占位符)。
我扩展了该解决方案,涵盖了GitHub 的 Gist上缺失的案例。您可以像当前的 AsyncImage 实现一样使用它,这样当它一致支持缓存时,您可以将其交换出来。
AsyncImage在底层使用默认的URLCache 。管理缓存最简单的方法是更改默认URLCache的属性
URLCache.shared.memoryCapacity = 50_000_000 // ~50 MB memory space
URLCache.shared.diskCapacity = 1_000_000_000 // ~1GB disk cache space
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30805 次 |
| 最近记录: |