【问题标题】:UITextField in custom UITableViewCell unexpectedly found nil自定义 UITableViewCell 中的 UITextField 意外发现 nil
【发布时间】:2018-03-01 10:04:52
【问题描述】:

我有一个 TableView 带有自定义单元格,里面有一个 TextField,不幸的是我得到一个 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value 当我使用它们时(按回车键或触摸文本字段外的屏幕以退出占位符)。

这是我的代码:

class WalletTableViewController: UIViewController, UITextFieldDelegate {

    var cryptosArray: [Cryptos] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self

        loadCryptoArray()
    }

    func loadCryptoArray() {

        if UserDefaults.standard.object(forKey: "cryptosArray") != nil {
            if let decoded = UserDefaults.standard.object(forKey: "cryptosArray") as? Data? {
               let decodedCryptoArray = NSKeyedUnarchiver.unarchiveObject(with: decoded!) as! [Cryptos]
               cryptosArray = decodedCryptoArray
        }
    } 
}

}

TableView 扩展:

extension WalletTableViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cryptosArray.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let crypto = cryptosArray[indexPath.row]

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! WalletTableViewCell
        cell.setCrypto(crypto: crypto)
        cell.delegate = self
        cell.amountTextField.delegate = self

        return cell
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 85
    }
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            cryptosArray.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)

            let userDefaults = UserDefaults.standard
            let encodedData : Data = NSKeyedArchiver.archivedData(withRootObject: cryptosArray)
            userDefaults.set(encodedData, forKey: "cryptosArray")
            userDefaults.synchronize()
        }
    }
}

这是TextField 的委托函数:

extension WalletTableViewController: CryptoCellDelegate {
    func cellAmountEntered(_ sender: Any) {
        if WalletTableViewCell().amountTextField.text == "" {
            return
        }
        let str = WalletTableViewCell().amountTextField.text

        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "en_US")
        let dNumber = formatter.number(from: str!)
        let nDouble = dNumber!
        let eNumber = Double(truncating: nDouble)

        WalletTableViewCell().amountLabel.text = String(format:"%.8f", eNumber)

      UserDefaults.standard.set(WalletTableViewCell().amountLabel.text, forKey: "bitcoinAmount")
        WalletTableViewCell().amountTextField.text = ""

    }
}

自定义单元格文件:

protocol CryptoCellDelegate {
    func cellAmountEntered(_ sender: Any)
}

class WalletTableViewCell: UITableViewCell {

    @IBOutlet weak var cryptoNameLabel: UILabel!
    @IBOutlet weak var amountLabel: UILabel!

    @IBOutlet weak var amountTextField: UITextField!

    var cryptoItem: Crypto!
    var delegate: CryptoCellDelegate?

    func setCrypto(crypto: Cryptos) {

        cryptoNameLabel.text = crypto.name
    }

    @IBAction func amountTextFieldEntered(_ sender: Any) {
        delegate?.cellAmountEntered((Any).self)
    }

}

TableView 拥有用户想要的尽可能多的单元格,因此这取决于创建单元格的对象的 array

我想我在某个地方遇到了delegate 问题?我对UITableView 很陌生,所以这是一个相当大的挑战,请原谅任何愚蠢的错误:)

PS:我试图通过删除 keyboard 函数和不相关的东西来保持代码简短,如果您需要其他内容,请告诉我。

【问题讨论】:

  • 更新extension WalletTableViewController: CryptoCellDelegate中的代码,因为它现在显然无法编译
  • 粘贴技巧不好,抱歉
  • 检查更新的答案
  • 也许你的文本字段的文本不是整数值测试这个let dNumber = Int(str) ? Int(str) : 0而不是这个let dNumber = formatter.number(from: str!)

标签: ios swift uitableview delegates uitextfield


【解决方案1】:

在您使用WalletTableViewCell() 的任何地方,您都在创建WalletTableViewCell 的新实例。发生崩溃是因为您以编程方式创建它,而 WalletTableViewCell 是使用情节提要设计的,并且由于您没有使用情节提要对其进行实例化,因此尚未设置 @IBOutlets,因此是 nil

更新

尝试使用它来修复它。将CryptoCellDelegate 更新为:

protocol CryptoCellDelegate {
    func cellAmountEntered(_ walletTableViewCell: WalletTableViewCell)
}

然后在WalletTableViewCell 更新amountTextFieldEntered 为:

@IBAction func amountTextFieldEntered(_ sender: Any) {
    delegate?.cellAmountEntered(self)
}

最后更新委托实现:

extension WalletTableViewController: CryptoCellDelegate {
    func cellAmountEntered(_ walletTableViewCell: WalletTableViewCell) {
        // now you can use walletTableViewCell to access the cell that called the delegate method
        if walletTableViewCell.amountTextField.text == "" {
            return
        }
        let str = walletTableViewCell.amountTextField.text

        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "en_US")
        let dNumber = formatter.number(from: str!)
        let nDouble = dNumber!
        let eNumber = Double(truncating: nDouble)

        walletTableViewCell.amountLabel.text = String(format:"%.8f", eNumber)

        UserDefaults.standard.set(walletTableViewCell.amountLabel.text, forKey: "bitcoinAmount")
        walletTableViewCell.amountTextField.text = ""

    }
}

【讨论】:

  • Milan 你好 :) 我以为我引用了WalletTableViewCell ,我真的需要再研究一下。我还认为委派函数足以使用WalletTableViewCell 出口和操作,这是否意味着我必须在WalletTableViewController 中再次声明所有内容?
  • @Martin33000 很高兴为您提供帮助
  • 作为建议@Martin33000,避免使用ClassName(),而是使用ClassName.init()。应该是一样的,然后教/提醒你,你每次都创建一个全新的对象,直到你吸收它。此外,由于该单元格与 XIB(或 Storyboard)链接,因此 IBOutlets 连接在那里,但没有该“UI 链接”就不会阻止您进行初始化。而且因为你做了init(),它没有创建一个与XIB链接的对象,所以Outlets是nil。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多