Skip to content

Instantly share code, notes, and snippets.

@cristhianleonli
Last active January 30, 2024 20:44
Show Gist options
  • Save cristhianleonli/6b9afb8effe9e73077d4b63e3bffcdb8 to your computer and use it in GitHub Desktop.
Save cristhianleonli/6b9afb8effe9e73077d4b63e3bffcdb8 to your computer and use it in GitHub Desktop.
import Foundation
import SwiftUI
struct CachedAsyncImage<Content, Placeholder>: View where Content: View, Placeholder: View {
@ViewBuilder private let content: (Image) -> Content
@ViewBuilder private let placeholder: () -> Placeholder
@ObservedObject var imageLoader: ImageLoader
init(
urlString: String,
@ViewBuilder content: @escaping (Image) -> Content,
@ViewBuilder placeholder: @escaping () -> Placeholder
) {
imageLoader = ImageLoader(urlString: urlString)
self.content = content
self.placeholder = placeholder
}
var body: some View {
if let image = imageLoader.image {
content(Image(uiImage: image))
} else {
placeholder()
}
}
}
struct Example: View {
private let gridItemLayout = [GridItem(.flexible(), spacing: 10)]
@State private var images = [
"https://via.placeholder.com/600/92c952"
]
var body: some View {
VStack(alignment: .leading) {
ScrollView(.horizontal, showsIndicators: false) {
LazyHGrid(rows: gridItemLayout) {
ForEach(images, id: \.self) { item in
CachedAsyncImage(
urlString: item,
content: { image in
image.resizable()
.scaledToFill()
},
placeholder: {
ProgressView()
}
)
.cornerRadius(50)
}
}
}
}
}
}
import Foundation
import UIKit
final class ImageCache {
static let shared = ImageCache()
private let cache = NSCache<NSString, UIImage>()
private init() {}
func set(_ image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as NSString)
}
func get(forKey key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
}
import Combine
import UIKit
final class ImageLoader: ObservableObject {
@Published var image: UIImage?
private var urlString: String
private var task: URLSessionDataTask?
init(urlString: String) {
self.urlString = urlString
loadImage()
}
private func loadImage() {
if let cachedImage = ImageCache.shared.get(forKey: urlString) {
self.image = cachedImage
return
}
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { [weak self, urlString] data, response, error in
guard let self, let data = data, error == nil else { return }
DispatchQueue.main.async {
if let image = UIImage(data: data) {
self.image = image
ImageCache.shared.set(image, forKey: urlString)
}
}
}
.resume()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment