Skip to content

Instantly share code, notes, and snippets.

@Joannis
Created October 31, 2024 06:59
Show Gist options
  • Select an option

  • Save Joannis/c237f8516a854cfd4acd5e7e36db9b0c to your computer and use it in GitHub Desktop.

Select an option

Save Joannis/c237f8516a854cfd4acd5e7e36db9b0c to your computer and use it in GitHub Desktop.
import SwiftUI
@MainActor class ViewModel: ObservableObject {
private let events = AsyncStream<AwaitableEvent>.makeStream()
struct AwaitableEvent {
let event: Event
let continuation: CheckedContinuation<Void, Never>
}
enum Event {
case loadSomeData
case exit
}
struct Post: Identifiable, Decodable {
let id: Int
let userId: Int
let title: String
let body: String
}
init() {
bind()
}
@Published var posts: [Post] = []
func send(_ event: Event) async {
return await withCheckedContinuation { continuation in
let awaitable = AwaitableEvent(
event: event,
continuation: continuation
)
events.continuation.yield(awaitable)
}
}
func bind() {
Task {
for await awaitable in self.events.stream {
switch awaitable.event {
case .loadSomeData:
try? await self.loadDataMainActor()
case .exit:
exit(0) // hoorayy!
}
awaitable.continuation.resume()
}
}
}
func loadDataMainActor() async throws{
posts = []
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!
let (data, _) = try await URLSession.shared.data(from: url)
do {
posts = try JSONDecoder().decode([Post].self, from: data)
} catch {
print("error=\(error)")
}
print("posts.count=\(posts.count)")
}
}
struct ContentView: View {
@StateObject var viewModel: ViewModel
var body: some View {
List(viewModel.posts) { row in
Text("Row \(row)")
}
.refreshable {
print("[aaa] Refreshable.start")
await viewModel.send(.loadSomeData)
print("[aaa] Refreshable.end")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment