简体   繁体   中英

SwiftUI View Not Updating to Reflect Data Changes in UIViewController

I've been experimenting with SwiftUI and UIKit, trying to understand how data is shared between the two frameworks, and I've created a simple example for a larger project I am working on. The example is a single SwiftUI view that contains a UIViewControllerRepresentatable wrapping a custom view controller. I am trying to have the SwiftUI view display the value of one of the view controller's properties, but it does not refresh correctly when the value is changed.

struct ContentView: View {
    @State var viewController = MyViewControllerRepresentable()
    var body: some View {
        VStack {
            viewController
            Text("super special property: \(viewController.viewController.data)")
        }
    }
}
class MyViewController: UIViewController, ObservableObject {
    @Published var data = 3

    override func viewDidLoad() {
        let button = UIButton(type: .system)
        button.setTitle("Increase by 1", for: .normal)
        button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
        view = button
    }

    @objc func buttonPressed() {
        data += 1
    }
}


struct MyViewControllerRepresentable: UIViewControllerRepresentable {
    @ObservedObject var viewController = MyViewController()

    func makeUIViewController(context: Context) -> UIViewController {
        return self.viewController
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

When I run the app and press the button, I can see that the actual value of data is changing, and the publisher in MyViewController is firing, but the value displayed on screen is not refreshed to reflect this.

Please note, I am very new to iOS development, and this is probably an unconventional data model. However, I don't see why it shouldn't work correctly. Suggestions for a better way to share data would be much appreciated, but I would primarily like to know if it is possible to get this working with its current data structure.

Thank you in advance.

You could create a @Binding . This means that when the value is updated for data , the views are recreated to reflect the changes.

Here is how it can be done:

struct ContentView: View {

    @State private var data = 3

    var body: some View {
        VStack {
            MyViewControllerRepresentable(data: $data)
            Text("super special property: \(data)")
        }
    }
}


class MyViewController: UIViewController {

    @Binding private var data: Int

    init(data: Binding<Int>) {
        self._data = data
        super.init(nibName: nil, bundle: nil)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func viewDidLoad() {
        let button = UIButton(type: .system)
        button.setTitle("Increase by 1", for: .normal)
        button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
        view = button
    }

    @objc func buttonPressed() {
        data += 1
    }
}


struct MyViewControllerRepresentable: UIViewControllerRepresentable {

    @Binding var data: Int
    private let viewController: MyViewController

    init(data: Binding<Int>) {
        self._data = data
        viewController = MyViewController(data: data)
    }


    func makeUIViewController(context: Context) -> UIViewController {
        viewController
    }
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM