Skip to content

Instantly share code, notes, and snippets.

@yamakk
Last active August 12, 2022 17:30
Show Gist options
  • Save yamakk/0ad25e2aae7f271b42aad273d5ebd169 to your computer and use it in GitHub Desktop.
Save yamakk/0ad25e2aae7f271b42aad273d5ebd169 to your computer and use it in GitHub Desktop.
Simplest MVVM with Combine
import Foundation
import SwiftUI
import Combine
struct API {
//private let url = URL(string: "https://hacker-news.firebaseio.com/v0/newstories.json")!
private let url = URL(string: "https://hacker-news.firebaseio.com/wrongendpoint")!
enum Error: LocalizedError, Identifiable {
var id: String { localizedDescription }
case addressUnreachable(URL)
case invalidResponse
var errorDescription: String? {
switch self {
case .invalidResponse:
return "The server responded with garbage 🗑"
case .addressUnreachable(let url):
return "\(url) is unreachable"
}
}
}
func request() -> AnyPublisher<[Int], API.Error> {
URLSession.shared.dataTaskPublisher(for: url)
.receive(on: DispatchQueue.main)
.map { $0.data }
.decode(type: [Int].self, decoder: JSONDecoder())
.mapError { error in
switch error {
case is URLError:
return Error.addressUnreachable(url)
default:
return Error.invalidResponse
}
}
.eraseToAnyPublisher()
}
}
class ViewModel: ObservableObject {
private let api = API()
private var subscriptions = Set<AnyCancellable>()
@Published var ids: [Int] = []
@Published var error: API.Error? = nil
func fetch() {
api.request()
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("finsihed")
case .failure(let error):
self.error = error
return print("🤮 \(error.localizedDescription)")
}
},
receiveValue: { ids in
self.ids = ids
})
.store(in: &subscriptions)
}
}
@main
struct MVVMApp: App {
private let model = ViewModel()
var body: some Scene {
WindowGroup {
ContentView(model: model)
.onAppear {
model.fetch()
}
}
}
}
struct ContentView: View {
@ObservedObject var model: ViewModel
var body: some View {
List(model.ids, id:\.self){ id in
Text("Story id")
Text(String(id)).padding()
}
.alert(item: self.$model.error) { error in
Alert(title: Text("🤮 Network Error"),
message: Text(error.localizedDescription),
dismissButton: .cancel())
}
}
}
@yamakk
Copy link
Author

yamakk commented Jan 18, 2022

Show Network Error alert.
Screen Shot 2022-01-18 at 12 32 58

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment