You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UICollectionView中自定义UITextField返回Nil,点击按钮App崩溃求助

Fixing Your UICollectionView Custom TextField Null & Crash Issues

Hey, let's break down what's going wrong here and fix it step by step:

Core Problems

  1. Your custom UITextField is returning nil because it's not being initialized correctly in your RBLoginCell class.
  2. The app crashes when tapping the login button because you're force-unwrapping nil references to your text fields (you never properly assigned those global txtFldUserId/txtFldPassword variables).

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:00:03