diff --git a/README.md b/README.md index 0415536..7f5aba8 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ A Swift package that provides elegant state management for asynchronous operatio AsyncLoad provides components for handling asynchronous operations: - `AsyncLoad`: For loading data operations +- `AsyncLoad` (without type): For operations that track loading state without data (uses `NoContent`) - `CachedAsyncLoad`: For loading operations that preserve cached data during refreshes - `AsyncLoadView`: A SwiftUI view component for displaying async states - `CachedAsyncLoadView`: A SwiftUI view component for cached async states @@ -80,6 +81,49 @@ class DataViewModel { } ``` +### AsyncLoad without Type Parameter (NoContent) + +For operations that need to track loading state but don't have any data to return, you can use `AsyncLoad` without a type parameter. This uses the `NoContent` type internally. + +```swift +public struct NoContent: Equatable, Sendable +public typealias AsyncLoadNoContent = AsyncLoad +``` + +This is useful for operations like: +- Delete operations +- Simple actions (e.g., mark as read, archive) +- Refresh operations without data +- Any operation where you only care about success/failure/loading state + +#### Example Usage + +```swift +import AsyncLoad + +@Observable +class ActionViewModel { + var deleteStatus: AsyncLoad = .none // No type parameter needed + + func deleteItem(id: String) async { + deleteStatus = .loading + + do { + try await itemService.deleteItem(id: id) + deleteStatus = .loaded // Convenience property for NoContent + } catch { + deleteStatus = .error(error) + } + } +} +``` + +You can also use the type alias explicitly: + +```swift +var deleteStatus: AsyncLoadNoContent = .none +``` + ### CachedAsyncLoad An enhanced version of AsyncLoad that preserves cached data during loading and error states. diff --git a/Sources/AsyncLoad/AsyncLoad/AsyncLoad+NoContent.swift b/Sources/AsyncLoad/AsyncLoad/AsyncLoad+NoContent.swift new file mode 100644 index 0000000..d857cef --- /dev/null +++ b/Sources/AsyncLoad/AsyncLoad/AsyncLoad+NoContent.swift @@ -0,0 +1,17 @@ +import Foundation + +public typealias AsyncLoadNoContent = AsyncLoad + +public struct NoContent: Equatable, Sendable { + public init() { } +} + +public extension AsyncLoad where T == NoContent { + init(_ type: AsyncLoad = .none) { + self = type + } + + static var loaded: AsyncLoad { + .loaded(NoContent()) + } +} diff --git a/Tests/AsyncLoadTests/AsyncLoad+NoContentTests.swift b/Tests/AsyncLoadTests/AsyncLoad+NoContentTests.swift new file mode 100644 index 0000000..dbd3d3b --- /dev/null +++ b/Tests/AsyncLoadTests/AsyncLoad+NoContentTests.swift @@ -0,0 +1,34 @@ +// +// AsyncLoad+NoContentTests.swift +// AsyncLoad +// +// Created by Alexander Kauer on 30.10.25. +// + +import Foundation +import Testing + +@Suite("Test no content AsyncLoad") +struct AsyncLoadNoContentTests { + + @Test<[AsyncLoadNoContentParameter]>("Should be equal", arguments: [ + .init(.none, .none), + .init(.loading, .loading), + .init(.loaded, .loaded), + .init(.error(TestingError.some), .error(TestingError.some)), + ]) + func noContentEqual(_ parameter: AsyncLoadNoContentParameter) { + #expect(parameter.load1 == parameter.load2) + } + + + @Test<[AsyncLoadNoContentParameter]>("Should not be equal", arguments: [ + .init(.none, .loading), + .init(.loading, .loaded), + .init(.loaded, .error(TestingError.some)), + .init(.error(TestingError.some), .none), + ]) + func noContentNotEqual(_ parameter: AsyncLoadNoContentParameter) { + #expect(parameter.load1 != parameter.load2) + } +} diff --git a/Tests/AsyncLoadTests/AsyncLoadEquatableItemTests.swift b/Tests/AsyncLoadTests/AsyncLoadEquatableItemTests.swift index d0a44fa..67c08f1 100644 --- a/Tests/AsyncLoadTests/AsyncLoadEquatableItemTests.swift +++ b/Tests/AsyncLoadTests/AsyncLoadEquatableItemTests.swift @@ -40,4 +40,6 @@ struct AsyncLoadEquatableItemTests { func nonEqualUser(param: AsyncLoadParameter) async throws { #expect(param.load1 != param.load2) } + + } diff --git a/Tests/AsyncLoadTests/Utils.swift b/Tests/AsyncLoadTests/Utils.swift index 7742343..e19d616 100644 --- a/Tests/AsyncLoadTests/Utils.swift +++ b/Tests/AsyncLoadTests/Utils.swift @@ -28,6 +28,16 @@ struct AsyncLoadParameter { } } +struct AsyncLoadNoContentParameter { + let load1: AsyncLoadNoContent + let load2: AsyncLoadNoContent + + init(_ load1: AsyncLoadNoContent, _ load2: AsyncLoadNoContent) { + self.load1 = load1 + self.load2 = load2 + } +} + struct CachedAsyncLoadParameter { let load1: CachedAsyncLoad let load2: CachedAsyncLoad