I am new to using xib files. So I'm not very clear on how they interact with their parent.
I have a custom view (LoginView) which is created from a xib file. This view also defines a protocol (LoginDelegate). The sole purpose of the delegate is to pass the username and password back to the caller.
I also have a ViewController (LoginVC) which implements this protocol. I am adding the LoginView to this VC.
I verified that I properly set the delegate in VC.viewDidLoad(). The problem is when I try to use the delegate to invoke the protocol method: the delegate is always nil. Somehow it is getting cleared. Here is the 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 {...}
}
And the View Controller:
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)")
}
}
The Connections for the Main Storyboard and Child xib, respectively:
I suspect I am not wiring things properly in IB, but I'm unsure. I have found many answers regarding this problem. I have tried many proposed solutions, but nothing works. I appreciate any input!
Create
class func getInstance() -> LoginView {
let nib = UINib(nibName:"LoginView", bundle:nil)
let view = nib.instantiate(withOwner: self, options: nil).first as! LoginView
return view
}
then
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)
Then remove this function loadViewFromNib
current problem when you do LoginView()
it creates an instance without it's layout and set the delegate for it but from your loadViewFromNib
you create another instance with correct layout and add it to that view but this misses delegate assignment hence the top subview of the view you create in the vc has a nil delegate
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.