How to use EnvironmentObject in UIKit ViewController
Asked Answered
N

1

6

I'm building a SwiftUI app that wraps UIKit ViewController through UIViewControllerRepresentable. The goal is to display a UITextView in my SwiftUI app. The implementation of this is simple, like this:

// iOSTextView.swift
import SwiftUI

struct iOSTextView: UIViewControllerRepresentable {
    @Binding var document: Document
    @EnvironmentObject var userData: UserData
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let view = iOSTextViewController()
        return view
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

    }
}

Notice the EnvironmentObject named UserData. It's a class that holds some general data that should be shared with every view in my app, including the UITextView ViewController.

// UserData.swift
import Foundation

final class UserData: ObservableObject  {
    @Published var someValue = 1
}

Below is my iOSTextViewController ViewController:

// iOSTextViewController.swift
import UIKit
import SwiftUI

class iOSTextViewController: UIViewController, UIGestureRecognizerDelegate {
    @EnvironmentObject var userData: UserData

    // Create a Text View
    let textView: UITextView = {
        let tv = UITextView()
        return tv
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Place the Text View on the view
        view.addSubview(textView)
        textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        
        // create attributed string
        let string = "This is a string."
        var attributes: [NSMutableAttributedString.Key: Any] = [
            .foregroundColor: UIColor.red,
            .font: UIFont(name: "Courier", size: 12)!
        ]
        let myAttrString = NSMutableAttributedString(string: string, attributes: attributes)
        textView.attributedText = myAttrString
    }    
}

My questions:

  1. How can I pass UserData to my ViewController named iOSTextViewController? Should I use a Coordinator? How can I use it to make the EnvironmentObject available and synchronized inside my ViewController?

  2. In the same way, how can I share my document binding, since it's a document-based app?

Nigercongo answered 19/12, 2020 at 17:13 Comment(2)
Did you get this to work? I have the same issue at the moment.Jodee
I just used @ObservedObject instead of @EnvironmentObject as a workaroundNigercongo
D
-3

This can be accomplished in SwiftUI relatively easily, to pass your UserData variable to any object you can make a Published variable in a separate class. Here is an example

class UserDataManager: ObservableObject { 

     @Published var userData: UserData = UserData(variable1, variable2...)

}

Then in your View struct you can simply do

struct TextView: View { 
    
   @ObservedObject var userDataManager = UserDataManager()

   var body : some View {
     
      TextField("Enter your data", text: $userDataManager.userData.name)
Disario answered 19/12, 2020 at 17:21 Comment(3)
Sorry but this is not what I'm asking about, I just edited my question to make it more clear.Nigercongo
Try using @ObservedObject instead?Disario
It's a very good idea, but isn't it possible to use @EnvironmentObject ?Nigercongo

© 2022 - 2024 — McMap. All rights reserved.