【问题标题】:How to assign value to an outlet after delegating it?委托后如何为出口分配价值?
【发布时间】:2022-01-26 06:16:20
【问题描述】:

所以我的应用有 3 个屏幕:Main、Second 和 Result(非常简单)

  • 在主屏幕上,我显示一个标签和按钮来更改它

  • 在第二个中,我使用 textinput 更改标签并将其传递给 Result (有

    导航控制器)

  • 在最后一个屏幕上,我显示了结果和 2 个按钮:保存和 取消

我的问题是我无法为 Main 的 outlet 赋值,因为它是 nil,我不能对 viewDidLoad() 做任何事情,因为它只在应用启动时工作一次。

我能做些什么来解决这个问题?是否有任何功能可以重新加载视图,以便我可以在 viewDidLoad 中分配值?

Storyboard screenshot

整个应用在这里:https://drive.google.com/file/d/1mvL2fVxjOHbL4dReCwJ8poIq9G9-ezny/view

主VC:

class MainVC: UIViewController, ResultVCDelegate {
    func passData(text: String) {
//        label.text = text   -- throws error
    }
    @IBOutlet weak var label: UILabel!
    @IBAction func change(_ sender: Any) {
        let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC")
        present(nextVC, animated: true, completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

第二个VC:

class SecondVC: UIViewController {
    @IBOutlet weak var inputText: UITextField!
    @IBAction func save(_ sender: Any) {
        let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ResultVC") as! ResultVC
        nextVC.labelText = inputText.text!
        navigationController?.pushViewController(nextVC, animated: true)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

结果VC:

protocol ResultVCDelegate {
    func passData(text: String)
}

class ResultVC: UIViewController {
    var delegate: ResultVCDelegate?
    var labelText = ""

    @IBOutlet weak var label: UILabel!
    @IBAction func saveAndGoHome(_ sender: Any) {
        let mainVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainVC") as! MainVC
        self.delegate = mainVC
        delegate?.passData(text: labelText)
        dismiss(animated: true, completion: nil)
    }
    @IBAction func cancel(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = labelText.isEmpty ? label.text : labelText
    }
}

顺便说一句:我用两个屏幕做了类似的应用程序,它就像一个魅力......奇怪

【问题讨论】:

  • 在您的 ResultVC 中,您创建了 MainVC 的一个新实例。这不是您的原始实例,如果需要,您需要传递对 ResultVC 的引用
  • 在实例化视图控制器后立即访问插座无法正常工作,因为视图尚未加载(尚未),这意味着插座未连接。
  • @Andrew 它可以工作,如果我将 print 放入 MainVC passData func 它会打印值
  • @vadian 听起来很奇怪,因为在 viewDidLoad() 中执行操作时它不起作用...

标签: ios swift delegates storyboard iboutlet


【解决方案1】:

继续我的评论。

查看您的代码,问题在于您没有将 MainVC 的引用传递给您的 ResultVC,而是创建了 MainVC 的新实例,这会导致崩溃,因为视图控制器没有正确创建的。但是您不想创建新实例,因为您需要对您创建的原始 MainVC 的引用。

您可以通过传递引用来获取此信息,您需要更新所有三个 ViewController。像这样的东西应该工作。请注意,我尚未对此进行测试,但这是一般原则。

class MainVC: UIViewController, ResultVCDelegate {
    func passData(text: String) {
        label.text = text
    }
    @IBOutlet weak var label: UILabel!
    @IBAction func change(_ sender: Any) {
        let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC")
        nextVC.delegate = self // Here we add the delegate (the reference to MainVC)
        present(nextVC, animated: true, completion: nil)
    }
}

我们需要在此处添加委托,然后将其转发到 ResultVC。

class SecondVC: UIViewController {

    weak var delegate: ResultVCDelegate? // Add the delegate that will hold a reference to MainVC
    
    @IBOutlet weak var inputText: UITextField!
    @IBAction func save(_ sender: Any) {
        let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ResultVC") as! ResultVC
        nextVC.labelText = inputText.text!
        nextVC.delegate = delegate // Here we pass the reference to MainVC
        navigationController?.pushViewController(nextVC, animated: true)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

我们可以从情节提要中删除用于实例化 MainVC 的代码,而只需使用委托将值传递回 MainVC。

class ResultVC: UIViewController {
    weak var delegate: ResultVCDelegate?
    var labelText = ""

    @IBOutlet weak var label: UILabel!
    @IBAction func saveAndGoHome(_ sender: Any) {
        // Just use the delegate no need to create a new instance
        delegate?.passData(text: labelText)
        dismiss(animated: true, completion: nil)
    }
    @IBAction func cancel(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = labelText.isEmpty ? label.text : labelText
    }
}

【讨论】:

  • 感谢您的回答。顺便说一句,我有连接到 SecondVC 的导航控制器。我怎样才能避免它?现在我通过调用导航控制器来调用 SecondVC
  • 您正在呈现然后推送,因此您需要在堆栈中使用导航控制器,如果您不想引用导航控制器,可以使用show,请参阅here更多信息
  • 抱歉,我必须稍微说明一下我的问题:我得到了连接所有 VC 所需的逻辑,但是如果我需要来自 SecondVC 的 NavigationController 怎么办?我也应该在 NC 中创建 var 委托吗?然后什么?介绍 SecondVC?
  • 导航控制器为您创建一个堆栈,因此您不必自己管理它,您不需要将委托传递给导航控制器,因为它不需要它。您只需要视图控制器中的委托(参考)。理想情况下,您应该以更好的方式编写应用程序,这样您就不必通过堆栈传递对 MainVC 的引用,而是在组合根处传递引用。但是,这样的解决方案超出了您原始问题的范围,不适合在 cmets 中讨论。
【解决方案2】:

-> Main VC(你需要获取数据的地方)

class MainVC: UIViewController, ResultVCDelegate {
        func passData(text: String) {
    //        label.text = text   -- throws error
        print(text)
        }
        @IBOutlet weak var label: UILabel!
        @IBAction func change(_ sender: Any) {
            let nextVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavVC")
            nextVC.delegate = self
            present(nextVC, animated: true, completion: nil)
        }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

-> 结果 VC(从您需要发送数据的地方)

protocol ResultVCDelegate: AnyObject {
    func passData(text: String)
}

class ResultVC: UIViewController {
    weak var delegate: ResultVCDelegate?
    var labelText = "Please Enter Something"

    @IBOutlet weak var label: UILabel!
    @IBAction func saveAndGoHome(_ sender: Any) {
        self.delegate?.passData(text: labelText)
        dismiss(animated: true, completion: nil)
    }
    @IBAction func cancel(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = labelText.isEmpty ? label.text : labelText
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 2011-09-15
    • 1970-01-01
    • 2013-04-12
    • 2015-11-18
    相关资源
    最近更新 更多