Skip to content

Instantly share code, notes, and snippets.

@tclementdev
Last active May 11, 2023 12:11
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tclementdev/c402bf5fddd8570287874333bc45a474 to your computer and use it in GitHub Desktop.
Save tclementdev/c402bf5fddd8570287874333bc45a474 to your computer and use it in GitHub Desktop.
import SwiftUI
// This is an example of how to keep the ObservableObjects near the root of the view hierarchy
// and dispatch actions from any view easily without having to pass too many things down. This
// helps keep the views simple and makes previews a lot easier.
//
// This is inspired from what Apple is doing with `DismissAction`, `OpenURLAction`, `OpenWindowAction`, etc...
// The following is a very simple example with only two view-levels and we could pass closures directly,
// but this gets really useful when dealing with complex view hierarchies that have many view levels.
struct ContentView: View {
@StateObject var controller = Controller()
var body: some View {
SubView()
.actions(controller.actions)
}
}
struct SubView: View {
@Environment(\.actions) var actions
var body: some View {
Button("create") {
let document = actions.create()
print("\(document.name)")
}
Button("send") {
Task {
let document = Document(name: "doc")
try await actions.send(document)
}
}
}
}
struct Document {
let name: String
}
final class Controller: ObservableObject {
var actions: Actions {
Actions(create: create, send: send(_:))
}
func create() -> Document {
// create some document
return Document(name: "doc")
}
func send(_ document: Document) async throws {
// send document here
}
}
struct Actions {
let create: () -> Document
let send: (Document) async throws -> Void
}
struct ActionsKey: EnvironmentKey {
static let defaultValue = Actions(create: { fatalError() }, send: { _ in fatalError() })
}
extension EnvironmentValues {
var actions: Actions {
get { self[ActionsKey.self] }
set { self[ActionsKey.self] = newValue }
}
}
extension View {
func actions(_ actions: Actions) -> some View {
environment(\.actions, actions)
}
}
@tclementdev
Copy link
Author

@helje5 actually, calling fatalError() for the default value of the environment key is not good, this causes SwiftUI previews to crash. I cannot use that.

@helje5
Copy link

helje5 commented May 11, 2023

Adjusted.

@tclementdev
Copy link
Author

yep, the two pieces are almost the same now :p

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