1

I have a UIKit ViewController that's nested inside a SwiftUI view using ViewControllerRepresentable. The SwiftUI view manages a bit of state (an Int, in this example) that I want to display in the UIKit view. When the user taps a button in the SwiftUI parent view, the state change should be reflected in the UIKit view. I've tried using the @Binding property wrapper to keep the two in sync, but clearly I'm missing something, as my view controller's initialiser throws a compile-time error.

I'm quite new to iOS development so perhaps I'm going in the complete wrong direction here. Any help would be greatly appreciated.

The code is as follows (simplified):

struct ContentView: View {
    @State private var currentNumber: Int

    init(currentNumber: Int) {
        self.currentNumber = currentNumber
    }

    var body: some View {
        FancyLabelViewControllerRepresentable(currentNumber: self.$currentNumber)
        Button("Increment") {
            self.currentNumber += 1
        }
    }
}

struct FancyLabelViewControllerRepresentable: UIViewControllerRepresentable {
    typealias UIViewControllerType = FancyLabelViewController

    @Binding var currentNumber: Int

    init(currentNumber: Binding<Int>) {
        self._currentNumber = currentNumber
    }

    func makeUIViewController(context: Context) -> FancyLabelViewController {
        let fancyLabel = FancyLabelViewController(number: self.currentNumber)
        fancyLabel.currentNumberInLabel = self.currentNumber
        return fancyLabel
    }

    func updateUIViewController(_ uiViewController: FancyLabelViewController, context: Context) {
        uiViewController.currentNumberInLabel = self.currentNumber
    }

}

class FancyLabelViewController: UIViewController {
    var label = UILabel()
    @Binding var currentNumberInLabel: Int

    init(number: Int) {
        // Error: 'self' used in property access 'currentNumberInLabel' before 'super.init' call
        self.currentNumberInLabel = number
        // Error: Property 'self.currentNumberInLabel' not initialized at super.init call
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder: NSCoder) {
        fatalError("Not implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = "\(currentNumberInLabel)"
        view = label
    }
}

1 Answer 1

2

I think you don't need the

@Binding var currentNumberInLabel: Int

because the UIViewControllerRepresentable already takes care of updating the currentNumberInLabel value, but you also needs to update the

label.text = "\(currentNumberInLabel)"

So I did something like

class FancyLabelViewController: UIViewController {
    var label = UILabel()
    var currentNumberInLabel: Int

    init(number: Int) {
        self.currentNumberInLabel = number
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder: NSCoder) {
        fatalError("Not implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = "\(currentNumberInLabel)"
        view = label
    }
  
    func updateLabel() {
      label.text = "\(currentNumberInLabel)"
    }
}

and call updateLabel from UIViewControllerRepresentable as

func updateUIViewController(_ uiViewController: FancyLabelViewController, context: Context) {
    uiViewController.currentNumberInLabel = self.currentNumber
    uiViewController.updateLabel()
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.