UITableView仅加载在设备上可见的自定义单元,并在添加一个以上单元时崩溃

时间:2019-04-18 12:51:10

标签: ios swift uitableview

我在自定义单元格中使用空的UITableView,并一一添加新项目,没有任何问题。 tableView是可滚动的,但是当我将一个项目添加到比最后一个可见单元格多一个索引的单元格时,应用程序崩溃。

加载应用程序时,numberOfRowsinSection为1,每增加一个新条目,它就会增加1。如果设备有10个可见单元格,则崩溃11。如果设备有6个可见单元格,则崩溃7。应用程序在解开Optional值时意外发现nil。

使用标题为UITableview Not scrolling?的问题中的建议 我在viewDidLoad和函数中尝试了以下每一行:

   self.myTableView.delegate = self

  self.myTableView.autoresizingMask = UIView.AutoresizingMask.flexibleHeight;

  self.myTableView.rowHeight = UITableView.automaticDimension

   self.myTableView.bounces = true;

  self.myTableView.reloadData()

没有任何积极的结果。

代码如下:

var enterCounts: Int = 1 

public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return enterCounts
    }

  public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TextInputCell") as! TextInputTableViewCell

        return cell
    }        


  @IBAction func enter(_ sender: Any) {

    let activeRow = self.enterCounts - 1
    let index = IndexPath(row: activeRow, section: 0)
    let cell: TextInputTableViewCell  = self.myTableView.cellForRow(at: index) as! TextInputTableViewCell


    if cell.myTextField.text == ""  {
         "DO NOTHING"
    } else {

        "DO STUFF"

        enterCounts += 1

        self.myTableView.reloadData()

        let nextIndex = IndexPath(row: activeRow + 1, section: 0)


 "This is the line that finds nil and crashes when row is out of view"

        let nextCell: TextInputTableViewCell = self.myTableView.cellForRow(at: nextIndex) as! TextInputTableViewCell
        nextCell.myTextField.text = ""
        nextCell.myTextField.becomeFirstResponder()
    }

}

我希望UITableView滚动并继续加载用户输入的单元格,与第一个/可见单元格完全一样。谢谢。

2个答案之后的代码是:

    @IBAction func enter(_ sender: Any) {

    let activeRow = self.enterCounts - 1
    let index = IndexPath(row: activeRow, section: 0)
    let cell: TextInputTableViewCell  = self.myTableView.cellForRow(at: index) as! TextInputTableViewCell


    if cell.myTextField.text == ""  {
         "DO NOTHING"
    } else {

        "DO STUFF"

      enterCounts += 1
      let nextIndex = IndexPath(row: activeRow + 1, section: 0) 
      self.myTableView.insertRows(at: [nextIndex], with: .automatic)
      self.myTableView.scrollToRow(at: nextIndex,at: .middle, animated: true)

     //These lines are executed only when I am in visible cells 
     //when a new cell is added it is not ready to become first responder it is skipped and entered text is getting mixed up.
 if let nextCell: TextInputTableViewCell = self.myTableView.cellForRow(at: nextIndex) as? TextInputTableViewCell {
            nextCell.myTextField.text = ""
            nextCell.myTextField.becomeFirstResponder()
           }
    }

}

在上面的代码中,新单元格完美地显示了出来,但对于出现在视图中的第一个单元格,textField仅成为第一响应者。

我在下面声明我的自定义单元格类

          @IBOutlet weak var myTextField: UITextField!

 public func configure(text: String?, placeholder: String) {


    myTextField.text = text
  //  myTextField.placeholder = placeholder

    myTextField.accessibilityValue = text
   // myTextField.accessibilityLabel = placeholder

}


override public func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
}

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

    // Configure the view for the selected state
}

如果我在tableView之外使用textField并仅保留tableView来显示输入的值,那么事情很简单,但是当我尝试使第一响应者成为新插入的单元格的textField时,tableView的最后一个单元格就产生了问题

3 个答案:

答案 0 :(得分:0)

如果您需要添加新单元格,则可以使用此行添加它:

let indexPath = IndexPath(row: ... , section: ...)
tableView.insertRows(at: [indexPath], with: .automatic)

滚动到它之后

   tableView.scrollToRow(at: indexPath,at: .middle, animated: true) 

最后,您可以使用此单元格

let cell = tableView.cellForRow(at: nextIndex) as! YourCustomCellClass

答案 1 :(得分:0)

它崩溃是因为Apple仅将可见的单元格保留在内存中。在您的情况下,您访问的是不在内存中的单元格,而是使用可选的选项来强制打开包装而导致崩溃。  知道这一点后,您应该为不可见的单元格处理异常,例如bewlow

@IBAction func enter(_ sender: Any) {

let activeRow = self.enterCounts - 1
let index = IndexPath(row: activeRow, section: 0)
let cell: TextInputTableViewCell  = self.myTableView.cellForRow(at: index) as! TextInputTableViewCell


if cell.myTextField.text == ""  {
     "DO NOTHING"
} else {

    "DO STUFF"

    enterCounts += 1

    self.myTableView.reloadData()

    let nextIndex = IndexPath(row: activeRow + 1, section: 0)


 //"This is the line that finds nil and crashes when row is out of view"

   if let nextCell: TextInputTableViewCell = self.myTableView.cellForRow(at: nextIndex) as? TextInputTableViewCell
{
    nextCell.myTextField.text = ""
    nextCell.myTextField.becomeFirstResponder()
}

}

如果您想使文本字段成为第一响应者,请先滚动到索引或插入它,然后再访问它,以获取内存中的单元格。

答案 2 :(得分:0)

如果您想在每次点击输入按钮时在表视图中添加新行,我认为您应该尝试采用这种方式

我假设您只是想在表视图中使用一个文本字段,但这也可以与其他东西一起使用 在您的自定义类中,为您的文本字段名称创建一个出口,无论您想要什么,我都将其命名为tf,然后执行

iboutlet weak var tf: uitextfield!{
didSet{
tf.delegate = self
}}

并创建一个这样的闭包

var textsaved: ((String) -> Void)?

然后将文本字段委托添加到您的customcell类中

extension CustomCell: uitextfielddelegate{ }

然后在您的扩展程序中写:

func textfieldshouldreturn(_ textfield: uitextfield) -> Bool{
tf.resignFirstResponder() 
retrun true }

func textfielddidendediting(_ textfield: uitextfield){
textsaved?(textfield.text!) }

然后在您的视图控制器中创建一个空字符串数组

var myarr = [String]()

为输入按钮和表格视图制作插座

@iboutlet weak var mytableview: uitableView!{
didSet{
mytableview.delegate = self
mytableview.datasource = self }

@iboutlet weak var enterBtn(_ sender: uibutton) {
myarr.append("")
mytableview.reloaddata() }

行数 返回myarr.count

在单元格中

let cell = tableview.dequereuseablecell(withidentifier: "cell", for :indexpath) as! customcell
cell.tf.text = myarr[indexpath.row]
cell.textsaved = { [unowned self] (text) in 
self.myarr.remove(at: indexpath.row)
self.myarr.insert(text, at: indexpath.row)
sel.mytableview.reloaddata()
} return cell }