English | 简体中文
An example demonstrating how to manage a single user's profile using MonoTask—with execution merging, TTL caching, and post-mutation refresh via forced execution.
- Platforms:
- iOS 13.0+
- macOS 10.15+
- tvOS 13.0+
- watchOS 6.0+
- Swift: 5.5+
- Dependencies:
- Monstra framework (local development version)
git clone https://github.com/yangchenlarkin/Monstra.git
cd Monstra/Examples/MonoTask/UserProfileManager# From the UserProfileManager directory
xed Package.swiftOr manually in Xcode:
- Open Xcode
- Go to
File → Open... - Navigate to the
UserProfileManagerfolder - Select
Package.swift(not the root Monstra project) - Click Open
This opens the example as a standalone Swift package.
Minimal model used for demonstration (see Sources/.../UserProfile.swift).
Simulates a single active user's profile with small artificial latency. Setters do not return the updated profile, so the app must fetch after setting.
enum UserProfileMockAPI {
static func getUserProfileAPI() async throws -> UserProfile { /* ... */ }
static func setUser(firstName: String) async throws { /* ... */ }
static func setUser(age: Int) async throws { /* ... */ }
}Wraps MonoTask<UserProfile> to manage a single cached profile with resultExpireDuration = 3600 seconds.
- Public API:
didLogin()— pre-warm cache (forceUpdate=false)setUser(firstName:)— set nickname, thenforceUpdate=trueto refreshsetUser(age:)— set age, thenforceUpdate=trueto refreshdidLogout()— cancel in-flight and clear cached result
main.swift demonstrates the flow by calling various methods and logging the results.
let manager = UserProfileManager()
print("trigger: didLogin")
manager.didLogin()
print("trigger set firstName: Alicia")
manager.setUser(firstName: "Alicia") { result in
switch result {
case .success:
print("Did set firstName: Alicia")
case .failure(let error):
print("Failed to set firstName: \(error)")
}
}- Execution Merging: multiple concurrent reads merge into one execution.
- TTL Caching: profile is cached for 1 hour.
- Forced Refresh: since setters return
Void, a fresh execution updates the cached profile. - State Management: Direct method calls with completion handlers for async operations.
From a sample run of this example:
update userProfile: nil
isLoading: false
trigger: didLogin
trigger set fistName: Alicia
isLoading: true
update userProfile: Optional(UserProfileManager.UserProfile(id: "1", nickName: "Alicia", age: 24))
isLoading: false
Did set firstName: Alicia
trigger set age: 10
isLoading: true
update userProfile: Optional(UserProfileManager.UserProfile(id: "1", nickName: "Alicia", age: 10))
isLoading: false
Did set age: 10
trigger didLogout
update userProfile: nil
Program ended with exit code: 0
- UserProfileManager: Data/state layer that wraps
MonoTaskand the mock API. - Domain Layer: Define a protocol if needed for DI and testing.
- Presentation Layer: UI/ViewModels call manager methods and handle completion callbacks.
Package.swift— SPM manifest (Monstra dependency)Sources/UserProfileManager/UserProfile.swift— domain modelSources/UserProfileManager/UserProfileMockAPI.swift— mocked data sourceSources/UserProfileManager/UserProfileManager.swift— manager wrappingMonoTaskSources/UserProfileManager/main.swift— method calls demo
MonoTask<UserProfile>withresultExpireDuration = 3600(1h TTL)- Post-mutation refresh via
asyncExecute(forceUpdate: true)keeping one-call-one-callback - Direct method calls with completion handlers for async operations
- Deterministic mock data for repeatable runs
