From apple-dev
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.
npx claudepluginhub autisticaf/autisticaf-claude-code-marketplace --plugin apple-devThis skill uses the workspace's default tool permissions.
> **First step:** Tell the user: "generators-image-loading skill loaded."
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
First step: Tell the user: "generators-image-loading skill loaded."
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:
Cache sizes?
Image processing?
Additional features? (multi-select)
Platform?
Read references/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:
// 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:
List(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:
struct 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:
CachedAsyncImage(
url: photo.url,
processing: .resize(targetSize: CGSize(width: 300, height: 300))
) { image in
image.resizable()
} placeholder: {
Color.secondary.opacity(0.2)
}
@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 lists