1

I have a SwiftUI view, which consists of a TextField. I want that whenever I type in the TextField it should send the value to the control on the UIKit UIViewController.

// Here is the ContentView 
class ContentViewDelegate: ObservableObject {

    var didChange = PassthroughSubject<ContentViewDelegate, Never>()

    var name: String = "" {
        didSet {
            self.didChange.send(self)
        }
    }
}

struct ContentView: View {

    @ObservedObject var delegate: ContentViewDelegate

    init(delegate: ContentViewDelegate) {
        self.delegate = delegate
    }

    var body: some View {
        VStack {
            TextField("Enter name", text: self.$delegate.name)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            }.padding()
        .background(Color.green)
    }
}

I checked didChange does get fired in the above code. But in the code below, the sink is never fired.

class ViewController: UIViewController {

    private var delegate = ContentViewDelegate()
    private var contentView: ContentView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.contentView = ContentView(delegate: self.delegate)

        let controller = UIHostingController(rootView: self.contentView)
        controller.view.translatesAutoresizingMaskIntoConstraints = false
        self.addChild(controller)
        self.view.addSubview(controller.view)
        controller.didMove(toParent: self)

        NSLayoutConstraint.activate([
            controller.view.widthAnchor.constraint(equalToConstant: 200),
            controller.view.heightAnchor.constraint(equalToConstant: 44),
            controller.view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            controller.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
        ])

        _ = self.delegate.didChange.sink { delegate in
            print(delegate.name)
        }

    }

Any ideas why didChange.sink is not getting fired?

2
  • You can't throw way the publisher any more (assign to _). Assign it to an AnyCancellable property Commented Apr 18, 2020 at 22:11
  • Thanks @Paulw11! I always forget that. That fixed the issue. If you can write as an answer I can accept it. Commented Apr 18, 2020 at 22:15

1 Answer 1

7

If you assign the publisher to _ then it is deallocated when viewDidLoad returns. Early examples from Apple show the assignment to _ and it used to work.

You need to ensure you keep a strong reference to your publisher using a property:

class ViewController: UIViewController {

    private var delegate = ContentViewDelegate()
    private var contentView: ContentView!
    private var textChangePublisher: AnyCancellable?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.contentView = ContentView(delegate: self.delegate)

        let controller = UIHostingController(rootView: self.contentView)
        controller.view.translatesAutoresizingMaskIntoConstraints = false
        self.addChild(controller)
        self.view.addSubview(controller.view)
        controller.didMove(toParent: self)

        NSLayoutConstraint.activate([
            controller.view.widthAnchor.constraint(equalToConstant: 200),
            controller.view.heightAnchor.constraint(equalToConstant: 44),
            controller.view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            controller.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
        ])

        self.textChangePublisher = self.delegate.didChange.sink { delegate in
            print(delegate.name)
        }

    }
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.