As you can see in the official tutorial project, there is this strange @EnvironmentObject
placed before var
. What does it mean?
struct LandmarkDetail: View {
@EnvironmentObject var userData: UserData
var landmark: Landmark
var landmarkIndex: Int {
userData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}
// ...
}
That's for example for Network purposes. You have a class conforming to BindableObject
(Beta 5: ObservableObject
) and send through the PassthroughSubject
(Beta 5: @Published
) your data.
For example this case:
SwiftUI (1.0)
struct Course: Decodable {
let name: String
}
class NetworkManager: ObservableObject {
@Published var courses = [Course]()
func getAllCourses() {
guard let url = URL(string: "https://api.letsbuildthatapp.com/jsondecodable/courses") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
let courses = try JSONDecoder().decode([Course].self, from: data!)
DispatchQueue.main.async {
self.courses = courses
}
} catch {
print("Failed To decode: ", error)
}
}.resume() // VERY IMPORTANT! As the request won't run
}
}
struct ContentView : View {
@ObservedObject var networkManager: NetworkManager = NetworkManager()
// Or this
// @EnvironmentObject var networkManager: NetworkManager // Don't forget to instaniate it with .environmentObject()
var body: some View {
VStack {
Button(action: {
self.networkManager.getAllCourses()
}, label: {
Text("Get All Courses")
})
List(networkManager.courses, id: \.name) {
Text($0.name)
}
}
}
}
Beta
struct Course: Decodable {
let name: String
}
class NetworkManager: BindableObject {
let didChange = PassthroughSubject<NetworkManager, Never>()
var courses = [Course]() {
didSet {
didChange.send(self)
}
}
func getAllCourses() {
guard let url = URL(string: "https://api.letsbuildthatapp.com/jsondecodable/courses") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
let courses = try JSONDecoder().decode([Course].self, from: data!)
DispatchQueue.main.async {
self.courses = courses
}
} catch {
print("Failed To decode: ", error)
}
}.resume() // VERY IMPORTANT! As the request won't run
}
}
struct ContentView : View {
@EnvironmentObject var networkManager: NetworkManager
var body: some View {
VStack {
Button(action: {
self.networkManager.getAllCourses()
}, label: {
Text("Get All Courses")
})
List(networkManager.courses.identified(by: \.name)) {
Text($0.name)
}
}
}
}
It’s designed to give your views access to the model automatically without the need for dependency injection.
Set the environment object once in the scene delegate then all views in the hierarchy have access to it via their own magic property. I believe it is also possible for a view to override the object for its children but I’ve not yet tested that yet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With