Ok,
so this might be trivial, but I am not sure how to go about this.
I have a UIViewController that gets created when the SwiftUI view calls:
func makeUIViewController(context: Context) -> MyViewController
The View that makes that call was given an environment object in the SceneDelegate like we have seen in the tutorials:
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(MyData()))
What I am trying to do is to use that environment object (MyData()) within my UIViewController logic. The ViewController would read/write on MyData's instance as needed, and from what I understand that should cause the SwiftUI view to react accordingly since MyData conforms to BindableObject...
So in the makeUIViewController call I get the UIViewControllerRepresentableContext. I can see the environment in the context:
context.environment
and if I print it in the console during debug I see this:
context.environment: [EnvironmentPropertyKey<PreferenceBridgeKey> = Value(value: Optional(SwiftUI.PreferenceBridge)), EnvironmentPropertyKey<FontKey> = Optional(SwiftUI.Font(provider: SwiftUI.(unknown context at $1c652cbec).FontBox<SwiftUI.Font.(unknown context at $1c656e2cc).TextStyleProvider>)), .......
In the print I see the MyData environmentObject instance:
EnvironmentPropertyKey<StoreKey<MyData>> = Optional(MyApp.MyData), ...
I am not sure how to get MyData out of the environment values given to me in the context.environment....
I have tried to figure out how to get the proper EnvironmentKey for MyData so I could try access it view subscript ... context.environment[myKey...]
How can I get MyData back from the environment values given to me by the context?
Using @EnvironmentObject now works (but not in Xcode Preview). Used Xcode 11.1/Swift 5.1. For simplicity it was used UIViewRepresentable, but the same should work for UIViewControllerRepresentable, because it is also SwiftUI View
Here is complete demo
import SwiftUI
import Combine
import UIKit
class AppState: ObservableObject {
@Published var simpleFlag = false
}
struct CustomUIView: UIViewRepresentable {
typealias UIViewType = UIButton
@EnvironmentObject var settings: AppState
func makeUIView(context: Context) -> UIButton {
let button = UIButton(type: UIButton.ButtonType.roundedRect)
button.setTitle("Tap UIButton", for: .normal)
button.actionHandler(controlEvents: UIControl.Event.touchUpInside) {
self.settings.simpleFlag.toggle()
}
return button
}
func updateUIView(_ uiView: UIButton, context: UIViewRepresentableContext<CustomUIView>) {
}
}
struct ContentView: View {
@ObservedObject var settings: AppState = AppState()
var body: some View {
VStack(alignment: .center) {
Spacer()
CustomUIView()
.environmentObject(self.settings)
.frame(width: 100, height: 40)
.border(Color.blue)
Spacer()
if self.settings.simpleFlag {
Text("Activated").padding().background(Color.red)
}
Button(action: {
self.settings.simpleFlag.toggle()
}) {
Text("SwiftUI Button")
}
.padding()
.border(Color.blue)
}
.edgesIgnoringSafeArea(.all)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(AppState())
}
}
/// Just utility below
extension UIButton {
private func actionHandler(action:(() -> Void)? = nil) {
struct __ { static var action :(() -> Void)? }
if action != nil { __.action = action }
else { __.action?() }
}
@objc private func triggerActionHandler() {
self.actionHandler()
}
func actionHandler(controlEvents control :UIControl.Event, for action:@escaping () -> Void) {
self.actionHandler(action: action)
self.addTarget(self, action: #selector(triggerActionHandler), for: control)
}
}
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