Skip to content

A SwiftUI view that emits asynchronous loading states: .idle, .loading, .loaded, and .failure.

License

Notifications You must be signed in to change notification settings

janodevorg/LoadingView

Repository files navigation

LoadingView

Swift

A SwiftUI view that emits asynchronous loading states: .idle, .loading, .loaded, and .failure.

@State private var loader = BlockLoadable {
    try await fetchData()
}

var body: some View {
    LoadingView(loader: loader) { value in
        Text("Success loading \(value)")
    }
    .emptyView {
        Text("Nothing here.")
    }
    .errorView { error in
        Text("Error: \(error.localizedDescription)")
    }
    .progressView { progress in
        ProgressView("\(progress.percent)% loaded")
    }
}

Use default loading and error views or pass your own. Data is loaded from a type conforming to the Loadable protocol. A few convenient implementations are provided:

Loaders are composable - you can nest them at will to combine behaviors like retry, debounce, and concurrency limiting. Example:

let searchLoadable = SearchableLoadable()
let debounced = await DebouncingLoadable(
    wrapping: searchLoadable,
    debounceInterval: 0.3
)
let retryable = RetryableLoader(
    base: debounced,
    maxAttempts: 2
)
let finalLoader = ConcurrencyLimitingLoadable(
    wrapping: retryable,
    concurrencyLimit: 1
)

Initial loading happens automatically, to prevent it pass loadOnAppear: false and call loader.load() later:

LoadingView(loader: loader, loadOnAppear: false) { value in
    ...
}

This library uses Swift 6. The v26 branch demonstrates usage of the native Observations framework available in iOS 26+.

Supported Versions

iOS 26+, macOS 26+, Xcode 16

Installation

Using Xcode Swift Package Manager

Using Xcode Swift Package Manager:

  1. In Xcode, select File > Add Packages...
  2. Enter URL: https://github.com/janodevorg/LoadingView.git
  3. Select the LoadingView library and add it to your target.

Using SPM

.package(url: "git@github.com:janodevorg/LoadingView.git", from: "1.0.3"),

.product(name: "LoadingView", package: "LoadingView"),

Development

To develop locally clone the repository and initialize submodules:

git clone https://github.com/janodevorg/LoadingView.git
cd LoadingView
git submodule init
git submodule update

Examples

See them in action in the Demo application.

Retry on Failure

Wrap any Loadable with RetryableLoader to automatically handle transient errors.

import LoadingView
import SwiftUI

// A loader that is designed to fail twice before succeeding
@State private var flakeyLoader = FlakeyLoader(successAfterAttempts: 3)

// Wrap it with RetryableLoader
@State private var retryableLoader = RetryableLoader(
    base: flakeyLoader,
    maxAttempts: 5
)

// Use it in your view
LoadingView(loader: retryableLoader) { message in
    Text(message)
}

Debounced Search

Wrap your search loader with DebouncingLoadable to prevent sending a network request on every keystroke.

import LoadingView
import SwiftUI

// A loader that performs a search
@State private var searchLoader = DebouncedSearchLoader()

// Wrap it with DebouncingLoadable
@State private var debouncedLoader = await DebouncingLoadable(
    wrapping: searchLoader,
    debounceInterval: 0.5 // 500ms
)

// In your view...
TextField("Search...", text: $searchText)
    .onChange(of: searchText) { newValue in
        searchLoader.searchText = newValue
        Task {
            // This load() call is debounced
            await debouncedLoader.load()
        }
    }

LoadingView(loader: debouncedLoader) { results in
    List(results, id: \.self) { Text($0) }
}

Documentation

There are some docs in the Docs/ folder.

Tip for AI-assisted development: If you encounter an issue while using this package with an AI coding agent, provide it with the relevant documentation files above. The docs contain detailed troubleshooting patterns and anti-patterns that help agents quickly identify and fix common problems.

About

A SwiftUI view that emits asynchronous loading states: .idle, .loading, .loaded, and .failure.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •