Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generates an image loading pipeline with memory/disk caching, deduplication, and a CachedAsyncImage SwiftUI view. Use when user wants image caching, lazy image loading, or a replacement for AsyncImage.
.claude/skills/rshankras-image-loading/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 56% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 43% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 36% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 92% | 0% |
Generate a production image loading pipeline with NSCache memory cache, LRU disk cache, request deduplication, image processing, and a drop-in CachedAsyncImage SwiftUI view.
Use this skill when the user:
Search for existing image loading:
Glob: **/*ImageCache*.swift, **/*ImageLoader*.swift, **/*ImagePipeline*.swift
Grep: "AsyncImage" or "UIImage" or "NSImage" or "ImageCache"If third-party library found (Kingfisher, SDWebImage, Nuke):
Determine if generating for iOS (UIImage) or macOS (NSImage) or both (cross-platform typealias).
Ask user via AskUserQuestion:
Read image-loading-patterns.md for architecture guidance. Read templates.md for production Swift code.
Generate these files:
ImageCache.swift — Protocol for cache interfaceMemoryImageCache.swift — NSCache-based with configurable sizeDiskImageCache.swift — FileManager LRU with expirationImageDownloader.swift — Actor-based with deduplication + cancellationImagePipeline.swift — Orchestrator (cache → download → process → store)CachedAsyncImage.swift — Drop-in SwiftUI view replacementBased on configuration:
ImageProcessor.swift — If resize or thumbnail selectedImagePrefetcher.swift — If prefetching selectedCheck project structure:
Sources/ exists → Sources/ImageLoading/App/ exists → App/ImageLoading/ImageLoading/After generation, provide:
ImageLoading/
├── ImageCache.swift # Protocol for cache interface
├── MemoryImageCache.swift # NSCache-based memory cache
├── DiskImageCache.swift # LRU disk cache with expiration
├── ImageDownloader.swift # Actor-based downloader
├── ImagePipeline.swift # Orchestrator
├── ImageProcessor.swift # Resize, thumbnails (optional)
├── CachedAsyncImage.swift # SwiftUI view
└── ImagePrefetcher.swift # Collection prefetching (optional)Drop-in replacement for AsyncImage:
swift// Before (no caching) AsyncImage(url: user.avatarURL) { image in image.resizable().aspectRatio(contentMode: .fill) } placeholder: { ProgressView() } // After (with caching) CachedAsyncImage(url: user.avatarURL) { image in image.resizable().aspectRatio(contentMode: .fill) } placeholder: { ProgressView() }
In a List:
swiftList(users) { user in HStack { CachedAsyncImage(url: user.avatarURL) { image in image.resizable().frame(width: 44, height: 44).clipShape(Circle()) } placeholder: { Circle().fill(Color.secondary.opacity(0.2)).frame(width: 44, height: 44) } Text(user.name) } }
With prefetching:
swiftstruct UsersListView: View { let users: [User] @State private var prefetcher = ImagePrefetcher() var body: some View { List(users) { user in UserRow(user: user) .onAppear { prefetcher.startPrefetching(urls: nearbyURLs(for: user)) } .onDisappear { prefetcher.stopPrefetching(urls: [user.avatarURL]) } } } }
With image processing:
swiftCachedAsyncImage( url: photo.url, processing: .resize(targetSize: CGSize(width: 300, height: 300)) ) { image in image.resizable() } placeholder: { Color.secondary.opacity(0.2) }
swift@Test func cachedImageReturnedWithoutDownload() async throws { let cache = InMemoryImageCache() let downloader = MockImageDownloader() let pipeline = ImagePipeline(cache: cache, downloader: downloader) let testImage = PlatformImage.testImage await cache.store(testImage, for: testURL) let result = try await pipeline.image(for: testURL) #expect(result != nil) #expect(downloader.downloadCount == 0) // Cache hit } @Test func deduplicatesConcurrentRequests() async throws { let downloader = MockImageDownloader(delay: .milliseconds(100)) let pipeline = ImagePipeline(downloader: downloader) async let image1 = pipeline.image(for: testURL) async let image2 = pipeline.image(for: testURL) let results = try await [image1, image2] #expect(results.count == 2) #expect(downloader.downloadCount == 1) // Only one download }
generators/http-cache — General HTTP response cachinggenerators/pagination — Prefetch images in paginated listsOther measured skills in the registry, with their headline benchmark lift.