Reputation: 1
I'm trying to dynamically insert rows into a UItableview to allow users to input a list. Inserting new rows works until I get to the bottom of the tableview. When I reach the bottom my fatal error triggers because the cell is the wrong type, this seems to be caused by the insert statement not being executed.
Here is my code for the tableview:
//
// TextEntryViewController.swift
// GroceryPlanner
//
// Created by Taygan Caldwell on 1/18/19.
// Copyright © 2019 None. All rights reserved.
//
import UIKit
class TextEntryViewController: UIViewController,UITextFieldDelegate,UITableViewDataSource,UITableViewDelegate {
//MARK: Properties
@IBOutlet weak var save: UIBarButtonItem!
@IBOutlet weak var tableView: UITableView!
var enteredItems=[String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource=self
tableView.delegate=self
// Do any additional setup after loading the view.
updateSaveButton()
}
//MARK: TableView Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return enteredItems.count+1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIndentifier="InputTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIndentifier, for: indexPath) as? InputTableViewCell else{
fatalError("wrong cell type")
}
cell.input.delegate=self
cell.input.tag=indexPath.row
if indexPath.row < enteredItems.count{
cell.input.text=enteredItems[indexPath.row]
}
return cell
}
//MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
let indexPath=IndexPath(row:enteredItems.count ,section:0)
tableView.insertRows(at: [indexPath], with: .automatic)
guard let cell=tableView.cellForRow(at: indexPath) as? InputTableViewCell else{
fatalError("wrong cell type")
}
cell.input.becomeFirstResponder()
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
textField.resignFirstResponder()
if textField.text != ""{
enteredItems.insert(textField.text!, at: enteredItems.count)
}
//refresh table
/*
self.tableView.reloadData()
let cell=getCell(enteredItems.count)
if cell.input.text != ""{
cell.input.text=""
}
*/
//enable save button if there is a least one item
updateSaveButton()
}
func textFieldDidBeginEditing(_ textField: UITextField) {
let index=textField.tag
let cell=getCell(index)
cell.becomeFirstResponder()
if index < enteredItems.count{
enteredItems.remove(at: index)
}
}
//MARK: Navigation
@IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
// This method lets you configure a view controller before it's presented.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let button=sender as? UIBarButtonItem, button===save else{
print("save button not pressed")
return
}
}
//MARK: Private Methods
private func updateSaveButton(){
save.isEnabled = !enteredItems.isEmpty
}
private func getCell(_ index:Int)->InputTableViewCell{
let indexPath=IndexPath(row: index,section:0)
guard let cell=tableView.cellForRow(at: indexPath) as? InputTableViewCell else{
fatalError("wrong cell type")
}
return cell
}
}
Upvotes: 0
Views: 106
Reputation: 631
Update 4. cellForRowAtIndexpath gives only the cell that is visible. 5. if tableview reaches bottom, then on every insert you have to call tableview.scrollToBottom. then you can get the cell for the last indexpath
By doing this way you will not be endup in fatal error.
Upvotes: 0
Reputation: 146
This should be executing before the method insertRows
if textField.text != ""{
enteredItems.insert(textField.text!, at: enteredItems.count)
}
This method is not called when you press return func textFieldDidEndEditing(_ textField: UITextField)
Upvotes: 1