Using Environmentobject in Watchos

Using environmentObject in watchOS

You can use type erasure, AnyView in the case of SwiftUI View.

I would refactor WKHostingController to return AnyView.

This seems to compile fine on my end.

class HostingController : WKHostingController<AnyView> {
override var body: AnyView {
return AnyView(ContentView().environmentObject(DataModel()))
}
}

How to inject .environmentObject() in watchOS6

The workaround from the link uses AnyView, which is a very bad idea. It has been explained in several other questions and tweets from Apple engineers, that AnyView should only be used on leaf views, as there is a heavy performance hit otherwise.

As for the second option (put the environmentObject inside ContentView), it works fine. Here you have an example:

class UserData: ObservableObject {
@Published var show: Bool = true
}

struct ContentView: View {
@State var model = UserData()

var body: some View {
SubView().environmentObject(model)
}
}

struct SubView: View {
@EnvironmentObject var model: UserData

var body: some View {
VStack {
Text("Tap Me!").onTapGesture {
self.model.show.toggle()
}

if self.model.show {
Text("Hello World")
}
}
}
}

How does SwiftUI pass EnvironmentObjects between HostingController?

Here is possible approach

class AppState: ObservableObject {
static let shared = AppState() // shared instance

@Published var setting: String = "some"
}

class HostingController: WKHostingController<AnyView> {
override var body: AnyView {
let contentView = ContentView()
.environmentObject(AppState.shared) // << inject !!
return AnyView(contentView)
}
}

class HostingController2: WKHostingController<AnyView> {
override var body: AnyView {
let contentView = ContentView2()
.environmentObject(AppState.shared) // << inject !!
return AnyView(contentView)
}
}

EnvironmentObject refresh/hand over problems using NavigationLink

One of the solutions is to create a variable controlling whether to display a navigation stack.

class AppStateControl: ObservableObject {
...
@Published var isDetailActive = false // <- add this
}

Then you can use this variable to control the first NavigationLink by setting isActive parameter. Also you need to add .isDetailLink(false) to all subsequent links.

First link in stack:

NavigationLink(destination: DetailView1().environmentObject(appStateControl), isActive: self.$appStateControl.isDetailActive) {
Text("Show Detail View 1")
}
.isDetailLink(false)

All other links:

NavigationLink(destination: DetailView2().environmentObject(appStateControl)) {
Text("Show Detail View 2")
}
.isDetailLink(false)

Then just set isDetailActive to false to pop all your NavigationLinks and return to the main view:

Button(action: {
self.appStateControl.callView = "AppMain"
self.appStateControl.isDetailActive = false // <- add this
}) {
Text("Go to main App")
}

WatchOS Using ObservableObject in Conditional in View Causing Runtime Error

I was having the same issue for a long time, and this is still happening on Xcode 13.2.1.

Seems to be an issue with TabView on watchOS, because if you replace the TabView for another View the error is gone.

The solution is to use the initialiser for TabView with a selection value: init(selection:content:)

1 Define a property for selection

@State private var selection = 0

2 Update TabView

From

TabView {
// content
}

To

TabView(selection: $selection) {
// content
}

Updating your code would look like this:

struct MultiPageView: View {
@StateObject var subscribed = SubscribedModel()
@State private var selection = 0

var body: some View {
if subscribed.value {
TabView(selection: $selection) {
ViewOne()
ViewTwo()
ViewThree()
ToggleView(subscribed: $subscribed.value)
}
.tabViewStyle(PageTabViewStyle())
} else {
TabView(selection: $selection) {
ViewOne()
ToggleView(subscribed: $subscribed.value)
}
.tabViewStyle(PageTabViewStyle())
}
}
}

Basically just defining a @State property for TabView.selection, and using it on both your TabViews (using separated properties would also work).

How do I access my model (or other state in the App struct) from a ComplicationController when using SwiftUI lifecycle?

As SomeModel is a single state object of the app, then you can just make it shared and access explicitly, like shown below

class SomeModel: ObservableObject {
static let shared = SomeModel()

// ... other code

so

@main
struct SomeApp: App {

@StateObject var model = SomeModel.shared // << here
...

and

class ComplicationController: NSObject, CLKComplicationDataSource {
var model = SomeModel.shared // << here
...

Note: EnvironmentObject works only in SwiftUI views, so in ComplicationController it is useless (or even harmful)



Related Topics



Leave a reply



Submit