I have a TableView
with custom cells that have a TextField
inside, unfortunately I get a Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value when I use them (press return or touch the screen outside the textField to get out of the placeholder).
Here is my code :
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
}
}
}
}
The TableView
extension :
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()
}
}
}
This is the delegate function for the 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 = ""
}
}
The custom cell file :
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)
}
}
The TableView
has as many cells as the user wants, so this is depending on the array
of objects that create the cells.
I guess I have a delegate
problem somewhere? I am quite new to UITableView
so this has been quite a challenge, forgive any stupid blunder :)
PS: I've tried to keep the code short by removing keyboard
functions and unrelated stuff, please tell me if you need something else.
Everywhere where you use
WalletTableViewCell()
you are creating a new instance of theWalletTableViewCell
. The crash happens because you are creating it programmatically, whileWalletTableViewCell
was designed using storyboards, and since you did not instantiated it using storyboards,@IBOutlet
s have not been set, therefore arenil
.Update
Try to fix it using this. Update
CryptoCellDelegate
to this:Then in
WalletTableViewCell
updateamountTextFieldEntered
to:And finally update delegate implementation: