init: init proj
This commit is contained in:
92
DDYSClient/Views/Common/CachedAsyncImage.swift
Normal file
92
DDYSClient/Views/Common/CachedAsyncImage.swift
Normal file
@@ -0,0 +1,92 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CachedAsyncImage<Placeholder: View>: View {
|
||||
let url: URL?
|
||||
@ViewBuilder let placeholder: () -> Placeholder
|
||||
|
||||
@State private var image: Image?
|
||||
@State private var isLoading = false
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
} else {
|
||||
placeholder()
|
||||
.task(id: url) {
|
||||
await loadImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadImage() async {
|
||||
guard let url, !isLoading else { return }
|
||||
|
||||
// 检查内存缓存
|
||||
if let cached = ImageCache.shared.get(url) {
|
||||
self.image = cached
|
||||
return
|
||||
}
|
||||
|
||||
isLoading = true
|
||||
defer { isLoading = false }
|
||||
|
||||
do {
|
||||
let (data, _) = try await ImageCache.shared.session.data(from: url)
|
||||
#if os(macOS)
|
||||
if let nsImage = NSImage(data: data) {
|
||||
let img = Image(nsImage: nsImage)
|
||||
ImageCache.shared.set(img, for: url)
|
||||
self.image = img
|
||||
}
|
||||
#else
|
||||
if let uiImage = UIImage(data: data) {
|
||||
let img = Image(uiImage: uiImage)
|
||||
ImageCache.shared.set(img, for: url)
|
||||
self.image = img
|
||||
}
|
||||
#endif
|
||||
} catch {
|
||||
// 加载失败保持 placeholder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 图片内存缓存
|
||||
|
||||
private final class ImageCache: @unchecked Sendable {
|
||||
static let shared = ImageCache()
|
||||
|
||||
private let cache = NSCache<NSURL, CacheEntry>()
|
||||
let session: URLSession
|
||||
|
||||
private init() {
|
||||
cache.countLimit = 200
|
||||
cache.totalCostLimit = 100 * 1024 * 1024 // 100MB
|
||||
|
||||
// 配置磁盘缓存
|
||||
let config = URLSessionConfiguration.default
|
||||
config.urlCache = URLCache(
|
||||
memoryCapacity: 50 * 1024 * 1024, // 50MB 内存
|
||||
diskCapacity: 200 * 1024 * 1024 // 200MB 磁盘
|
||||
)
|
||||
config.requestCachePolicy = .returnCacheDataElseLoad
|
||||
session = URLSession(configuration: config)
|
||||
}
|
||||
|
||||
func get(_ url: URL) -> Image? {
|
||||
cache.object(forKey: url as NSURL)?.image
|
||||
}
|
||||
|
||||
func set(_ image: Image, for url: URL) {
|
||||
cache.setObject(CacheEntry(image: image), forKey: url as NSURL)
|
||||
}
|
||||
}
|
||||
|
||||
private final class CacheEntry {
|
||||
let image: Image
|
||||
init(image: Image) { self.image = image }
|
||||
}
|
||||
Reference in New Issue
Block a user