【问题标题】:Protocol delegate is always nil协议委托始终为零
【发布时间】:2020-04-13 03:17:10
【问题描述】:

我不熟悉使用 xib 文件。所以我不太清楚他们如何与父母互动。

我有一个从 xib 文件创建的自定义视图 (LoginView)。这个视图还定义了一个协议(LoginDelegate)。委托的唯一目的是将用户名和密码传回给调用者。

我还有一个实现此协议的 ViewController (LoginVC)。我正在将 LoginView 添加到这个 VC。

我确认我在 VC.viewDidLoad() 中正确设置了委托。问题是当我尝试使用委托来调用协议方法时:委托始终为零。不知何故,它正在被清除。这是 UIView:

// MARK:- Login Delegate method
// provide a means to pass the user credentials back to the parent
protocol LoginDelegate: AnyObject {
    func getUsernameAndPassword(user: String, pwd: String)
}

class LoginView: UIView, UITextViewDelegate {

    @IBOutlet weak var user: UITextView!
    @IBOutlet weak var password: UITextView!
    @IBOutlet weak var btnLogin: UIButton!
    var userPlaceholderLabel : UILabel!
    var pwdPlaceholderLabel : UILabel!
    var view: UIView!

    weak var loginDelegate: LoginDelegate?


    // MARK:- internal use only
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    class func getInstance() -> LoginView {
      let nib = UINib(nibName:"LoginView", bundle:nil)
      let view = nib.instantiate(withOwner: self, options: nil).first as! LoginView
      return view
    }

    @IBAction func onLoginButtonPress(_ sender: Any) {
        print ("\(#function): Username: \(user.text ?? ""), Password: \(password.text ?? "")")

        self.loginDelegate?.getUsernameAndPassword(user: user.text, pwd: password.text )
    }

    // MARK:- TextView Delegate methods
    func textViewDidChange(_ textView: UITextView) {...}  
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {...}
}

还有视图控制器:

class LoginVC: UIViewController, LoginDelegate {

    var isBleScan = true
    @IBOutlet weak var btnToggleBleScan: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        let loginSubview = LoginView.getInstance()
        loginSubview.frame = self.view.bounds
        loginSubview.loginDelegate = self
        view.addSubview(loginSubview)
    }

    @IBAction func onToggleScanPressed(_ sender: Any) {
        isBleScan = !isBleScan
        if (isBleScan) {
            btnToggleBleScan.setTitle("Stop Scan", for: UIControl.State.normal)
        } else {
            btnToggleBleScan.setTitle("Start Scan", for: UIControl.State.normal)
        }
    }

    // MARK:- LoginDelegate methods
// METHOD IS NEVER CALLED - DELEGATE IS nil IN THE CALLER
    func getUsernameAndPassword(user: String, pwd: String) {
        let _user = user
        let _pwd = pwd
        print ("\(#function):Username: \(_user), Password: \(_pwd)")        
    }
}

主故事板和子 xib 的连接分别为:

我怀疑我在 IB 中没有正确接线,但我不确定。我找到了很多关于这个问题的答案。我尝试了许多建议的解决方案,但没有任何效果。感谢您的意见!

【问题讨论】:

  • viewDidLoad 中,您没有从 xib 初始化您的 LoginView。您也没有使用框架对其进行初始化。不确定您正在点击哪个按钮,但它不在您正在 viewDidLoad 中初始化的视图中。您的 onLoginButtonPress 函数中还有一个额外的 }。

标签: ios swift uiview delegates xib


【解决方案1】:

创建

  class func getInstance() -> LoginView { 
    let nib = UINib(nibName:"LoginView", bundle:nil)
    let view = nib.instantiate(withOwner: self, options: nil).first as! LoginView
    return view
  }

然后

    let loginSubview = LoginView.getInstance()
    loginSubview.frame = self.view.bounds
    loginSubview.loginDelegate = self   // I verified this sets the delegate to an instance of LoginVC
    view.addSubview(loginSubview)

那就去掉这个功能loadViewFromNib


当前问题,当您执行 LoginView() 时,它会创建一个没有布局的实例并为其设置委托,但您可以从您的 loadViewFromNib 创建另一个具有正确布局的实例并将其添加到该视图,但这会错过委托分配,因此您在 vc 中创建的视图的顶部子视图有一个 nil 委托

【讨论】:

  • 感谢您的解释 - 这很有意义。我已经更新了我的问题以反映您的建议。我现在得到一个不同的错误。 “由于未捕获的异常'NSUnknownKeyException'而终止应用程序,原因:'[ setValue:forUndefinedKey:]:此类不符合密钥密码的密钥值编码。”我已对所有插座和操作进行了未连线/重新连线,但我得到了同样的错误。我仍然怀疑接线。 LoginView 委托应该连接到文件所有者还是 LoginVC?我添加了连接的屏幕截图。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多