Skip to content

Instantly share code, notes, and snippets.

@x0000ff
Last active April 29, 2024 17:07
Show Gist options
  • Save x0000ff/9d7fbf5c6bee06b5e192c84e43cb2eba to your computer and use it in GitHub Desktop.
Save x0000ff/9d7fbf5c6bee06b5e192c84e43cb2eba to your computer and use it in GitHub Desktop.
Custom @Environment Objects (aka Apple DI Container)

Trying the trick that @azamsharp shared here and here

In Action:

Mocked Real
import SwiftUI
struct Post: Decodable, Identifiable {
let id: Int
let title: String
}
protocol HttpClientProtocol {
func fetchPosts() async throws -> [Post]
}
class HttpClient: HttpClientProtocol {
func fetchPosts() async throws -> [Post] {
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([Post].self, from: data)
}
}
class MockedHttpClient: HttpClientProtocol {
func fetchPosts() async throws -> [Post]{
return [Post(id: 1, title: "Post #1"), Post(id: 2, title: "Post #2")]
}
}
struct HttpClientEnvironmentKey: EnvironmentKey {
static var defaultValue: HttpClientProtocol = HttpClient()
}
extension EnvironmentValues {
var httpClient: (HttpClientProtocol) {
get { self[HttpClientEnvironmentKey.self] }
set { self[HttpClientEnvironmentKey.self] = newValue }
}
}
struct ContentView: View {
@Environment(\.httpClient) private var httpClient
@State private var posts: [Post] = []
var body: some View {
VStack {
List(posts) { post in
Text(post.title)
}.task {
do {
posts = try await httpClient.fetchPosts()
} catch {
print(error.localizedDescription)
}
}
}
}
}
#Preview {
ContentView()
.environment(\.httpClient, MockedHttpClient())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment