UICollectionView中自定义UITextField返回Nil,点击按钮App崩溃求助
Hey, let's break down what's going wrong here and fix it step by step:
Core Problems
- Your custom
UITextFieldis returningnilbecause it's not being initialized correctly in yourRBLoginCellclass. - The app crashes when tapping the login button because you're force-unwrapping
nilreferences to your text fields (you never properly assigned those globaltxtFldUserId/txtFldPasswordvariables).
1. Fix the TextField Initialization in RBLoginCell
Looking at your RBLoginCell code, the getTextField method requires a frame parameter, but you're calling it without passing any value in the initializer:
// Your broken init code override init(frame: CGRect) { super.init(frame: frame) txtFld = getTextField() // ❌ No frame passed to a method that expects one separator = getImageView() }
This means txtFld is never actually created, hence it's always nil. Let's fix the getTextField method to work without a parameter (we'll use the cell's frame directly):
Updated getTextField Method
func getTextField() -> CustomTextField? { // Use the cell's frame to set up the text field's initial bounds let textFieldFrame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height - 1) let textField = CustomTextField(frame: textFieldFrame) textField.borderStyle = .none textField.placeholder = "" textField.backgroundColor = UIColor.clear textField.autocorrectionType = .no textField.keyboardType = .default textField.returnKeyType = .next textField.enablesReturnKeyAutomatically = false textField.clearButtonMode = .never textField.text = "" textField.contentVerticalAlignment = .center textField.autocapitalizationType = .none textField.alpha = 1.0 textField.isUserInteractionEnabled = true // Set up left label let lblleft = getLabel() lblleft?.frame = CGRect(x: 0, y: 20, width: self.frame.size.width, height: self.frame.size.height) lblleft?.backgroundColor = UIColor.clear lblleft?.text = "\n+91" lblleft?.font = UIFont(name: Constants.HelveticaNeue, size: 14) lblleft?.textColor = UIColor(hexString: "555555") textField.leftView = lblleft textField.leftViewMode = .never addSubview(textField) return textField }
Fix the Initializer
Now call the updated method correctly:
override init(frame: CGRect) { super.init(frame: frame) txtFld = getTextField() // ✅ No parameter needed now separator = getImageView() }
2. Fix the Login Action Crash
Your loginAction method uses global txtFldUserId and txtFldPassword variables, but you never assigned them to the actual text fields in your collection view cells. The local variables you created in cellForItemAt don't update the global ones, so they stay nil. Force-unwrapping nil with ! causes the crash.
Instead, fetch the cells directly from the collection view and safely access their text fields:
Updated loginAction Method
func loginAction(sender: UIButton!) { // Safely get the email cell and its text guard let emailCell = collectionView.cellForItem(at: IndexPath(row: 0, section: 0)) as? RBLoginCell, let emailText = emailCell.txtFld?.text, !emailText.isEmpty else { // Show error: Please enter your email return } // Safely get the password cell and its text guard let passwordCell = collectionView.cellForItem(at: IndexPath(row: 1, section: 0)) as? RBLoginCell, let passwordText = passwordCell.txtFld?.text, !passwordText.isEmpty else { // Show error: Please enter your password return } // Proceed with login user?.emailAddress = emailText user?.password = passwordText postLoginRequest(user) }
We use guard let here to safely unwrap optional values—this avoids crashes and lets you handle empty input cases gracefully.
Bonus: Clean Up cellForItemAt
Avoid force-unwrapping collectionView and indexPath here too, to make your code more robust:
func accountCollectionView(_ collectionView: UICollectionView?, cellForItemAt indexPath: IndexPath?) -> UICollectionViewCell? { guard let collectionView = collectionView, let indexPath = indexPath else { return nil } let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RBLoginCell", for: indexPath) as! RBLoginCell cell.backgroundColor = UIColor.clear switch indexPath.row { case 0: configureTextField(cell.txtFld, placeholder: "Email Address", tag: 1, keyboardType: .emailAddress, returnKeyType: .next, isSecure: false) case 1: configureTextField(cell.txtFld, placeholder: "Password", tag: 2, returnKeyType: .done, isSecure: true) default: break } cell.setNeedsLayout() return cell } // Helper method to reduce code duplication private func configureTextField(_ textField: CustomTextField?, placeholder: String, tag: Int, keyboardType: UIKeyboardType = .default, returnKeyType: UIReturnKeyType, isSecure: Bool) { textField?.delegate = self textField?.placeholder = placeholder textField?.tag = tag textField?.keyboardType = keyboardType textField?.returnKeyType = returnKeyType textField?.isSecureTextEntry = isSecure }
This makes your code cleaner and less error-prone.
内容的提问来源于stack exchange,提问作者Chandan

