Skip to content
Skills Library
Programming · Building & coding

image-loading

/image-loading

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.

Licence
MIT
Last repository change
24.07.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
3
Scripts
0
HTML comments
0
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 24.07.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What it does and when to use it

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.

Original author description

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.

How it works

  1. When This Skill Activates
  2. Pre-Generation Checks
  3. Configuration Questions
  4. Generation Process
  5. Output Format
  6. References
Original SKILL.md headings · 204 lines, 761 words
SKILL.md preview
---
name: image-loading
description: 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.
allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, AskUserQuestion]
last_verified: 2026-07-16
review_by: 2027-06-22
os_version: iOS 27 / macOS 27
---

# Image Loading Generator

Generate a production image loading pipeline with NSCache memory cache, LRU disk cache, request deduplication, image processing, and a drop-in `CachedAsyncImage` SwiftUI view.

## When This Skill Activates

Use this skill when the user:
- Asks to "add image caching" or "cache images"
- Wants to "replace AsyncImage" or fix "AsyncImage has no cache"
- Mentions "image loading pipeline" or "lazy image loading"
- Asks about "image download" or "image prefetching"
- Wants "thumbnail generation" or "image resizing"

## Pre-Generation Checks

### 1. Project Context Detection
- [ ] Check Swift version (requires Swift 5.9+)
- [ ] Check deployment target (iOS 16+ / macOS 13+)
- [ ] Check for @Observable support (iOS 17+ / macOS 14+)
- [ ] Identify source file locations

### 2. Conflict Detection
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):
- Ask if user wants to replace or keep it
- If keeping, don't generate — advise on best practices instead

### 3. Platform Detection
Determine if generating for iOS (UIImage) or macOS (NSImage) or both (cross-platform typealias).

## Configuration Questions

Ask user via AskUserQuestion:

1. **Cache sizes?**
   - Small (50 MB memory / 100 MB disk)
   - Medium (100 MB memory / 250 MB disk) — recommended
   - Large (200 MB memory / 500 MB disk)

2. **Image processing?**
   - Resize to fit (downscale large images to save memory)
   - Thumbnail generation (create small thumbnails for lists)
   - None (cache original images only)

3. **Additional features?** (multi-select)
   - Prefetching for collections (preload images for visible rows + buffer)
   - Placeholder and error images
   - Progress indicator during download

4. **Platform?**
   - iOS only
   - macOS only
   - Cross-platform (iOS + macOS)

## Generation Process

### Step 1: Read Templates
Read `image-loading-patterns.md` for architecture guidance.
Read `templates.md` for production Swift code.

### Step 2: Create Core Files
Generate these files:
1. `ImageCache.swift` — Protocol for cache interface
2. `MemoryImageCache.swift` — NSCache-based with configurable size
3. `DiskImageCache.swift` — FileManager LRU with expiration
4. `ImageDownloader.swift` — Actor-based with deduplication + cancellation
5. `ImagePipeline.swift` — Orchestrator (cache → download → process → store)

### Step 3: Create UI Files
6. `CachedAsyncImage.swift` — Drop-in SwiftUI view replacement

### Step 4: Create Optional Files
Based on configuration:
- `ImageProcessor.swift` — If resize or thumbnail selected
- `ImagePrefetcher.swift` — If prefetching selected

### Step 5: Determine File Location
Check project structure:
- If `Sources/` exists → `Sources/ImageLoading/`
- If `App/` exists → `App/ImageLoading/`
- Otherwise → `ImageLoading/`

## Output Format

After generation, provide:

### Files Created
```
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)
```

### Integration Steps

**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:**
```swift
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:**
```swift
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:**
```swift
CachedAsyncImage(
    url: photo.url,
    processing: .resize(targetSize: CGSize(width: 300, height: 300))
) { image in
    image.resizable()
} placeholder: {
    Color.secondary.opacity(0.2)
}
```

### Testing

```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
}
```

## References

- **image-loading-patterns.md** — Why not AsyncImage, NSCache config, LRU disk cache, deduplication
- **templates.md** — All production Swift templates
- Related: `generators/http-cache` — General HTTP response caching
- Related: `generators/pagination` — Prefetch images in paginated lists
Files in this package (3)
  • SKILL.md 6 KB
  • image-loading-patterns.md 10 KB
  • templates.md 18 KB

Versions

The database has no other skills named image-loading.

Database snapshot: 13.11.2026 · package version 19fc5bad394c (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 95coil-compose
    Use when loading images in Compose or Compose Multiplatform with Coil 3 — AsyncImage vs SubcomposeAsyncImage vs rememberAsyncImagePainter, ImageRequest configuration, placeholder/error states, performance in lists, and KMP setup with LocalPlatformContext.
  • 100lazy-loading-implementer
    Execute lazy loading implementer operations. Auto-activating skill for Frontend Development. Triggers on: lazy loading implementer, lazy loading implementer Part of the Frontend Development skill category. Use when working with lazy loading implementer functionality. Trigger…
  • 100kirby-performance-and-media
    Improves Kirby performance and media delivery (cache tuning, CDN, responsive images, lazy loading). Use when optimizing page speed, caching, or image handling.
  • 95swiftui-performance
    Audit and improve SwiftUI runtime performance. Use when diagnosing slow rendering, janky scrolling, high CPU, memory usage, excessive view updates, layout thrash, body evaluation cost, identity churn, view lifetime issues, lazy loading, Instruments profiling guidance, and performance audit requests.
  • 100offscreen-lazy
    Use when reviewing image assets, markup, and CDN or build transforms related to Lazy load offscreen images. Check encoded size, rendered size, loading strategy, and above-the-fold impact together. Missing `loading='lazy'` is only a valid finding when you can reasonably tell the…
  • 100performance-optimization
    Optimize application performance for speed, efficiency, and scalability. Use when improving page load times, reducing bundle size, optimizing database queries, or fixing performance bottlenecks. Handles React optimization, lazy loading, caching, code splitting, and profiling.

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.