SwiftlyImageLoader

1.1.0

A fast, cross-platform Swift image loader with caching, cancellation, and UI integrations for UIKit, AppKit, and SwiftUI.
mohsinbmwm3/SwiftlyImageLoader

What's New

πŸ”– Version 1.1.0 – Cache-Aware, Transformable, Cross-Platform

2025-05-10T17:24:03Z

πŸš€ Major enhancements to flexibility and reliability in SwiftlyImageLoader

✨ What’s New

  • πŸ•“ Custom Cache Expiration (TTL): Fine-grained memoryCacheTTL and diskCacheTTL let you control how long images stay cached in RAM and on disk
ImageLoader.setup(with: SwiftlyImageLoaderConfiguration(
      memoryCacheTTL: 60,     // 60 seconds
      diskCacheTTL: 86400     // 1 day
))
  • πŸŒ€ Transform Hooks: Apply custom resizing, cropping, grayscale, or circular masks before caching or display
  • 🧠 Cross-platform ImageTransforms: Reusable, type-safe closures for both UIImage and NSImage
  • πŸ“± SwiftUI Support: SwiftlyAsyncImage now supports transformation via transform: closure
  • πŸ’‘ Sendable-Safe: Fully Swift 6-compliant, using @Sendable closures and MainActor.run where needed
  • πŸͺ„ Automatic shape rendering: New circular(size:) ensures transform fits UI container exactly

πŸ› Bug Fixes

  • 🐞 Fixed issue where transforms didn’t apply on first load due to layout timing
  • πŸ”„ Ensured consistency of transformed image caching across memory and disk layers
  • πŸ’₯ Fixed MainActor concurrency errors when accessing view bounds inside closures

πŸ“¦ Update Instructions

If using transforms that depend on layout (e.g. .circular(size:)), be sure to:

let size = imageView.bounds.size
imageView.setImage(from: url, transform: ImageTransforms.circular(for: size))

SwiftlyImageLoader

A lightweight, fast, and highly configurable Swift image loading library with built-in caching and cancellation. Works seamlessly with UIKit, AppKit, and SwiftUI β€” making it suitable for iOS, macOS, tvOS, and watchOS applications.


πŸš€ Features

  • 🧠 Smart in-memory & disk caching
  • 🧹 Automatic cancellation for reused views
  • πŸŽ›οΈ Configurable via SwiftlyImageLoaderConfiguration
  • βœ… Retry logic and TTL configuration
  • 🧩 Modular targets: UIKit / AppKit / SwiftUI
  • πŸ›  Zero dependencies, pure Swift
  • πŸ“ˆ Great for performance-sensitive use cases (e.g. fast-scrolling lists)

🧠 How It Works – Caching Flow

When you request an image:

Request Image
   ↓
Check in-memory cache (fast, volatile)
   ↓
If not found β†’ Check disk cache (persistent)
   ↓
If not found β†’ Download from network
   ↓
Save to memory + disk caches for future use
  • Memory Cache (ImageCache) β†’ uses NSCache, evicts on memory pressure
  • Disk Cache (DiskCache) β†’ saves across app launches, TTL-aware

This ensures blazing-fast UI (via RAM) + reduced network usage (via disk).


βš™οΈ Configuration Example

ImageLoader.setup(with: SwiftlyImageLoaderConfiguration(
  memoryCacheTTL: 60,              // In-memory cache expires after 60 seconds
  diskCacheTTL: 86400,             // Disk cache expires after 24 hours
  autoCancelOnReuse: true,         // Cancel previous task for reused views
  enableBatchCancelation: true,    // Allows cancelAll() to stop all loading tasks
  logLevel: .verbose                // Enables verbose logging for debugging
))

πŸ“¦ Installation

Swift Package Manager (SPM)

Add this line to your Package.swift:

.package(url: "https://github.com/mohsinbmwm3/SwiftlyImageLoader.git", from: "1.0.0")

Then add one or more of the following modules to your target:

.product(name: "SwiftlyImageLoader", package: "SwiftlyImageLoader"),
.product(name: "SwiftlyImageLoaderUIKit", package: "SwiftlyImageLoader"),
.product(name: "SwiftlyImageLoaderAppKit", package: "SwiftlyImageLoader"),
.product(name: "SwiftlyImageLoaderSwiftUI", package: "SwiftlyImageLoader")

πŸ›  Configuration

Customize behavior via the SwiftlyImageLoaderConfiguration:

ImageLoader.setup(with: SwiftlyImageLoaderConfiguration(
    autoCancelOnReuse: true,
    enableBatchCancelation: true,
    logLevel: .verbose
))

Available Options

Property Description
autoCancelOnReuse Cancels prior image loads for the same URL automatically
enableBatchCancelation Allows cancelling all tasks via ImageLoader.cancelAll()
logLevel Controls log verbosity (none, basic, verbose)

πŸ“± UIKit Usage

import SwiftlyImageLoaderUIKit

imageView.setImage(from: URL(string: "https://picsum.photos/id/45/800/600"))

Supports:

  • Placeholder images
  • Image reuse cancellation via config
  • Memory & disk cache fallback

πŸ–₯ macOS AppKit Usage

import SwiftlyImageLoaderAppKit

imageView.setImage(from: URL(string: "https://picsum.photos/id/55/1200/800"))

πŸ§‘β€πŸŽ¨ SwiftUI Usage

import SwiftlyImageLoaderSwiftUI

SwiftlyAsyncImage(url: URL(string: "https://picsum.photos/id/33/600/400"))

πŸ“ Folder Structure

Sources/
β”œβ”€β”€ SwiftlyImageLoader          // Core engine, caching, config
β”œβ”€β”€ SwiftlyImageLoaderUIKit     // UIImageView extensions
β”œβ”€β”€ SwiftlyImageLoaderAppKit    // NSImageView extensions
β”œβ”€β”€ SwiftlyImageLoaderSwiftUI   // SwiftlyAsyncImage wrapper

πŸ§ͺ Performance Testing

Use Instruments to track:

  • Memory spikes
  • Network reuse / caching hit rates
  • Logging behavior with .verbose mode

Use .cancelAll() in viewDidDisappear() for clean teardown.


πŸ“„ License

MIT Β© Mohsin Khan

Description

  • Swift Tools 6.0.0
View More Packages from this Author

Dependencies

  • None
Last updated: Fri May 16 2025 21:33:22 GMT-0900 (Hawaii-Aleutian Daylight Time)