Last active
October 22, 2024 13:53
-
-
Save Codelaby/e5dd4aaefed37a8741f932b92d5073d4 to your computer and use it in GitHub Desktop.
Prefetch big images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct RemotePhotoDemoModel: Identifiable { | |
let id: UUID = .init() | |
let image: String | |
var imageData: Data? | |
static let allPhotos: [RemotePhotoDemoModel] = [ | |
//RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1531737212413-667205e1cda"), // error sample | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1510001618818-4b4e3d86bf0f"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1504284992506-f6d82d0f2f2a"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1465447142348-e9952c393450"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1675826460422-e39481fae224"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661964121314-cb43af3580a1"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1514920735211-8c697444a248"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1547981609-4b6bfe67ca0b"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1517309230475-6736d926b979"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1510423579098-f47bf52b6764"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1474181487882-5abf3f0ba6c2"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1508804052814-cd3ba865a116"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661962892760-5e50359c5123"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1529020503594-28b8a4f004bd"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1528163186890-de9b86b54b51"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1465935607384-d6a9087be24a"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1520745947248-e287a72ed646"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1517248980687-80aa4dfd5218"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1508043157312-69e4bf3dd28c"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1531981462953-7cea7af328e0"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1603384446936-5646a2481a36"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1542554250-726628a42330"), | |
RemotePhotoDemoModel(image: "https://cdn.pixabay.com/photo/2020/05/29/04/28/chinese-5233524_1280.jpg"), | |
RemotePhotoDemoModel(image: "https://cdn.pixabay.com/photo/2016/07/20/05/14/wulingyuan-1529632_1280.jpg"), | |
RemotePhotoDemoModel(image: "https://cdn.pixabay.com/photo/2017/08/14/07/37/china-2639590_1280.jpg"), | |
RemotePhotoDemoModel(image: "https://cdn.pixabay.com/photo/2015/03/19/10/43/china-680715_1280.jpg"), | |
RemotePhotoDemoModel(image: "https://cdn.pixabay.com/photo/2022/03/26/14/54/chongqing-7093033_1280.jpg"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1524413840807-0c3cb6fa808d"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1542051841857-5f90071e7989"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1545569341-9eb8b30979d9"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1540959733332-eab4deabeeaf"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1528181304800-259b08848526"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1506665531195-3566af2b4dfa"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1519915247718-1703f9c6bb15"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661962958462-9e52fda9954d"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1531169628939-e84f860fa5d6"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1673288456074-ef3c61ca27f4"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661854008793-8ce54b2e622b"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1504457047772-27faf1c00561"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1504699439244-a7e34870c35d"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1559592413-7cec4d0cae2b"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1516484681091-7d83961805f4"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/flagged/photo-1549874613-8ea0adee1a82"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1712455498779-2a82e9d4b41a"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661963095864-01a3dbb82d90"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661916287718-edb15703cbaf"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1641573337436-90557fdd9604"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1552058185-28aa65f3bbaf"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1465056836041-7f43ac27dcb5"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1507699622108-4be3abd695ad"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1462759353907-b2ea5ebd72e7"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1523049820105-c2e73204bac1"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1494500764479-0c8f2919a3d8"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1618811213393-5f399dab320e"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1695197974761-431794d2a415"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1713945305643-89f7b4cbc076"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1715229001649-d6fbb422fa1a"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1729299960640-f56dac79d34e"), | |
RemotePhotoDemoModel(image: "https://images.unsplash.com/photo-1623253436564-5786debfccad"), | |
RemotePhotoDemoModel(image: "https://plus.unsplash.com/premium_photo-1661882377491-c5685537447f") | |
] | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import Nuke //https://github.com/kean/Nuke | |
@MainActor | |
@Observable | |
class RemotePhotoViewModel { | |
var photos: [RemotePhotoDemoModel] = [] | |
private let pipeline = ImagePipeline.shared | |
init() { | |
self.photos = RemotePhotoDemoModel.allPhotos | |
} | |
func downloadImage(for photo: RemotePhotoDemoModel) async throws { | |
print("⬇️ downloadImage", photo.image) | |
guard let index = self.photos.firstIndex(where: { $0.id == photo.id }) else { return } | |
let request = ImageRequest( | |
url: URL(string: photo.image)!, | |
processors: [.resize(width: 320)], | |
priority: .high | |
) | |
let image = try await pipeline.image(for: request) | |
if let imageData = image.pngData() { | |
self.photos[index].imageData = imageData | |
let sizeInBytes = imageData.count | |
print("✅ downloadImage", photo.image, "Size: \(sizeInBytes) bytes", "set index \(index)") | |
} else { | |
print("⚠️ downloadImage", photo.image, "Failed to convert image to PNG data") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ScrollWithRemoteImages: View { | |
@State private var viewModel = RemotePhotoViewModel() | |
var body: some View { | |
let _ = Self._printChanges() | |
ScrollView(.vertical) { | |
LazyVStack { | |
ForEach(viewModel.photos, id: \.id) { photo in | |
VStack { | |
if let imageData = photo.imageData, let image = UIImage(data: imageData) { | |
photoView(image: Image(uiImage: image)) | |
} else { | |
VStack { | |
Spacer() | |
ProgressView() | |
Spacer() | |
} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background(.regularMaterial) | |
.aspectRatio(4 / 3, contentMode: .fit) | |
.onAppear { | |
Task { | |
try await viewModel.downloadImage(for: photo) | |
} | |
} | |
} | |
} | |
.id(photo.id) | |
} | |
} | |
.scrollTargetLayout() | |
} | |
} | |
@ViewBuilder | |
private func photoView(image: Image) -> some View { | |
Rectangle() | |
.overlay(alignment: .center) { | |
image | |
.resizable() | |
.scaledToFill() | |
} | |
.aspectRatio(4 / 3, contentMode: .fit) | |
.clipped() | |
} | |
} | |
#Preview { | |
ScrollWithRemoteImages() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment