Search code examples
iosswiftmacosnstextfield

Changing Label text on main controller after modal closed swift macOS


I am using delegates to get a string value from my modal. When the modal closes I am trying to update Label text using that string. However, I am getting error: Unexpectedly found nil while implicitly unwrapping an Optional value: file. I am not sure how to fix this. I think it's happening because the view is not yet active.

import Cocoa

class ViewControllerA: NSViewController, SomeDelegate {
    @IBOutlet weak var msgLabel: NSTextField!

    var s: String = "";

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    func setDetails(s: String) {
        self.user = s;
        print("Notified", self.s) // <-- prints: Notified hello again
        msgLabel.stringValue = self.s <-- DOESN'T WORK
    }


    func showModal() -> Void {

        msgLabel.stringValue = "hello" // <--- WORKS
        let cbvc: NSViewController = {
            return self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
            as! NSViewController
        }()

        self.presentAsModalWindow(cbvc);
    }

    @IBAction func onBtn(_ sender: Any) {
        self.showModal();
    }
}

protocol SomeDelegate {
    func setDetails(s: String)
}


class ViewControllerB: NSViewController {

    @IBOutlet weak var textF: NSTextField!

    var delegate: SomeDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        let vc = ViewControllerA()
        self.delegate = vc
    }

    @IBAction func onBtn(_ sender: Any) {
        DispatchQueue.main.async {
                        self.delegate?.setDetails(s: self.textF.stringValue)
                        self.dismiss("ControllerAVC")
                    }
    }
}

Solution

  • You have a number of problems.

    In ViewControllerB.viewDidLoad you are assigning a new instance of ViewControllerA to the delegate property. Don't do that. Your viewDidLoad method should look like this:

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    

    In the showModal method ViewControllerA should assign itself as the delegate on ViewControllerB before ViewControllerB it is presented.

    func showModal() -> Void {
        let cbvc: NSViewController = {
            let vc = self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
            as! ViewControllerB
            vc.delegate = self
            return vc
        }()
    
        self.presentAsModalWindow(cbvc);
    }
    

    In the setDetails method just assign the string to your text field directly:

    func setDetails(s: String) {
        msgLabel.stringValue = s
    }