How to use EnvironmentObject in SwiftUI for watchOS

Issue #467

Declare top dependencies in ExtensionDelegate

1
2
3
4
5
6
7
class ExtensionDelegate: NSObject, WKExtensionDelegate {
let storeContainer = StoreContainer()

func applicationDidEnterBackground() {
storeContainer.save()
}
}

Reference that in HostingController. Note that we need to change from generic MainView to WKHostingController<AnyView> as environmentObject returns View protocol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class HostingController: WKHostingController<AnyView> {
var storeContainer: StoreContainer!

override func awake(withContext context: Any?) {
super.awake(withContext: context)
self.storeContainer = (WKExtension.shared().delegate as! ExtensionDelegate).storeContainer
}

override var body: AnyView {
return AnyView(MainView()
.environmentObject(storeContainer)
)
}
}

In theory, the environment object will be propagated down the view hierarchy, but in practice it throws error. So a workaround now is to just pass that environment object down manually

Fatal error: No ObservableObject of type SomeType found
A View.environmentObject(_:) for StoreContainer.Type may be missing as an ancestor of this view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct MainView: View {
@EnvironmentObject var storeContainer: StoreContainer

var body: some View {
VStack {
List(services.map({ AnyService($0) })) { anyService in
NavigationLink(destination:
ItemsView(service: anyService.service)
.navigationBarTitle(anyService.service.name)
.onDisappear(perform: {
anyService.service.requestCancellable?.cancel()
})
.environmentObject(storeContainer)
) {
HStack {
Image(anyService.service.name)
.resizable()
.frame(width: 30, height: 30, alignment: .leading)
Text(anyService.service.name)
}
}
}.listStyle(CarouselListStyle())
}
}
}

Updated at 2020-06-26 03:54:01

Comments