致命错误:在展开可选值时意外发现 nil - 当 UITextField 被点击时

Posted

技术标签:

【中文标题】致命错误:在展开可选值时意外发现 nil - 当 UITextField 被点击时【英文标题】:fatal error: unexpectedly found nil while unwrapping an Optional value - when UITextField is tapped 【发布时间】:2016-01-22 12:14:16 【问题描述】:

我在其中一个 UITableViewCell 行中有一个 UITextField。当我选择该行时,将调用文本字段的委托方法。但是,当我直接点击 UITextField 时,应用程序崩溃并出现以下错误,

致命错误:在展开可选值时意外发现 nil

只有在点击 UITextField 时应用才会崩溃。使用给定数据正确加载了 tableView。

这是代码,

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")

    cell.detailTextLabel?.hidden = true

    let txtFld = UITextField()
    cell.contentView.addSubview(txtFld)
    txtFld.tintColor = appGlobals.appThemeColor
    txtFld.delegate = self
    txtFld.textColor = appGlobals.appThemeColor
    txtFld.returnKeyType = UIReturnKeyType.Done
    txtFld.keyboardType = UIKeyboardType.EmailAddress
    txtFld.autocorrectionType = UITextAutocorrectionType.No
    txtFld.autocapitalizationType = UITextAutocapitalizationType.None
    txtFld.translatesAutoresizingMaskIntoConstraints = false
    txtFld.text = self.appGlobals.getSelectedContactEmail()
    txtFld.tag = 99
    cell.addConstraint(NSLayoutConstraint(item: txtFld, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: cell.textLabel, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 15))
    cell.addConstraint(NSLayoutConstraint(item: txtFld, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: cell.frame.size.width - 30))
    cell.addConstraint(NSLayoutConstraint(item: txtFld, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 20))
    cell.addConstraint(NSLayoutConstraint(item: txtFld, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: cell.textLabel, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0))

    cell.selectionStyle = UITableViewCellSelectionStyle.None

    return cell


func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
    let txtField = cell.viewWithTag(99) as! UITextField
    txtField.becomeFirstResponder()

还有 UITextField 委托方法,

func textFieldShouldBeginEditing(textField: UITextField) -> Bool 
    return true


func textFieldDidBeginEditing(textField: UITextField) 
    NSLog("text field became first responder")

更新1:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")

    cell.detailTextLabel?.hidden = true
    if(cell.contentView.viewWithTag(99) == nil)
        let txtFld = UITextField()
        cell.contentView.addSubview(txtFld)
        txtFld.tintColor = appGlobals.appThemeColor
        txtFld.delegate = self
        txtFld.textColor = appGlobals.appThemeColor
        txtFld.returnKeyType = UIReturnKeyType.Done
        txtFld.keyboardType = UIKeyboardType.EmailAddress
        txtFld.autocorrectionType = UITextAutocorrectionType.No
        txtFld.autocapitalizationType = UITextAutocapitalizationType.None
        txtFld.text = self.appGlobals.getSelectedContactEmail()
        txtFld.tag = 99

        cell.selectionStyle = UITableViewCellSelectionStyle.None

        return cell
    


func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
    if let txtField = cell.contentView.viewWithTag(99) as? UITextField 
        txtField.becomeFirstResponder()
    

更新 2:

这是自定义表格视图单元格的代码,

import UIKit

class TxtFieldTableViewCell: UITableViewCell 

let appGlobals = AppGlobals()

let txtFld = UITextField(frame: CGRectMake(15, 27, AppGlobals().getScreenWidth() - 30, 20))

override init(style: UITableViewCellStyle, reuseIdentifier: String?) 
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    txtFld.tintColor = appGlobals.appThemeColor
    txtFld.textColor = appGlobals.appThemeColor
    txtFld.returnKeyType = UIReturnKeyType.Done
    txtFld.autocorrectionType = UITextAutocorrectionType.No
    txtFld.autocapitalizationType = UITextAutocapitalizationType.None
    self.addSubview(txtFld)


required init?(coder aDecoder: NSCoder) 
    fatalError("init(coder:) has not been implemented")


override func awakeFromNib() 
    super.awakeFromNib()


override func setSelected(selected: Bool, animated: Bool) 
    super.setSelected(selected, animated: animated)



我已经在我的代码中这样使用它,

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    var cell : TxtFieldTableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? TxtFieldTableViewCell

    if cell == nil 
        cell = TxtFieldTableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")
    

    if(cell!.viewWithTag(99) == nil)
        cell!.txtFld.delegate = self
        cell!.txtFld.keyboardType = UIKeyboardType.EmailAddress
        cell!.txtFld.text = self.appGlobals.getSelectedContactEmail()
        cell!.txtFld.tag = 99
        cell!.selectionStyle = UITableViewCellSelectionStyle.None
    

仍然遇到同样的错误。

【问题讨论】:

崩溃发生在哪一行? 我怀疑文本字段未正确启动 UITextField()。尝试用一些框架来初始化它,比如 UITextField(frame: someRect) 也可以试试 cell.contentView.viewWithTag(99)。请注意,txtField 是 contentView 的子视图,而不是单元格。 此代码不是最优的。每次调用cellForRowAtIndexPath 时,您都会创建一个新的文本字段并将其添加到表格视图单元格中......如果您正在滚动该表格视图,单元格会被重用,文本字段会一遍又一遍地添加到相同的(回收)细胞。您可能应该想出一种不同的方式来添加您的文本字段(例如子类 UITableViewCell?)。 没有特定的行发生崩溃。如果直接点击 UITextField,则应用程序崩溃。 @RamyKfoury 【参考方案1】:

你的代码中唯一可能发生错误的地方就是这个

let txtField = cell.viewWithTag(99) as! UITextField
txtField.becomeFirstResponder()

请改成以下,再试一次

if let txtField = cell.contentView.viewWithTag(99) as? UITextField 
    txtField.becomeFirstResponder()

如果这解决了问题,那么您的 TextField 没有很好地启动...尝试给它一个类似的框架

txtFld.frame = CGRectMake(0,0,40,40)

在将其添加为子视图之前

另外看看 Michael Dautermanns 的评论... TableViewCells 被重用了...所以你需要检查是否已经有标签为 99 的子视图,如果没有标签为 99 的子视图,则只添加一个新的子视图

【讨论】:

感谢您的回复。我已经尝试过你的建议。但是,我仍然遇到同样的错误。请检查我更新的帖子。 您没有设置文本字段的委托 我做到了。但是委托方法没有被调用@pbush25 我已经用 UITextField 委托方法更新了我的帖子。请检查它@pbush25 你的类没有声明自己符合 UITextViewDelegate【参考方案2】:

我找到了我的应用程序崩溃的原因。我在 textFieldShouldBeginEditing 中使用了一个未初始化的变量。该变量是在 didSelectRowAtIndexPath 方法中初始化的。

我已经声明了一个这样的变量,

var selectedIndex: NSIndexPath!

我已经这样初始化了,

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
    let cell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
    selectedIndex = indexPath
    if let txtField = cell.viewWithTag(99) as? UITextField 
        txtField.becomeFirstResponder()
    

而变量是这样使用的,

func textFieldShouldBeginEditing(textField: UITextField) -> Bool 
    if(selectedIndex.section != 0)
          //Some Operation
    

由于当我直接点击文本字段时selectedIndex 没有初始化,所以我的应用程序崩溃了。这就是问题所在。

感谢@Michael Dautermann 和@Neo 提出最佳解决方案。

【讨论】:

以上是关于致命错误:在展开可选值时意外发现 nil - 当 UITextField 被点击时的主要内容,如果未能解决你的问题,请参考以下文章

Alamofire,致命错误:在展开可选值时意外发现 nil

奇怪的“致命错误:在展开可选值时意外发现 nil”

Swift 物理致命错误:当两个字符发生碰撞时,在展开可选值时意外发现 nil

如何防止致命错误:在展开可选值时意外发现 nil

致命错误:在展开可选值时意外发现 nil - 为啥?

swift - bgMusic - 致命错误:在展开可选值时意外发现 nil