使用自定义 UITableViewCell 中的按钮获取单元格字符串的问题 [英] Issue with getting cell's string using a button in a custom UITableViewCell

查看:23
本文介绍了使用自定义 UITableViewCell 中的按钮获取单元格字符串的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用自定义 UITableViewCell 中的按钮获取单元格的 string.但是当我点击按钮时,由于此错误应用程序崩溃:致命错误:解包可选值时意外发现 nil .

I am trying to get cells' string using a button in a custom UITableViewCell.But when I tap the button app crashes due to this error : fatal error: unexpectedly found nil while unwrapping an Optional value .

我尝试了 print 一些东西并且它有效!但是当我尝试让其他单元格的字符串应用程序崩溃时.这是我的代码:

I tried print something and it works!.but when I try to get other cells' string app crashes. Here is my code :

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

  var cellID:String!
      var cell = OrderCell()

      switch indexPath.section {
          .
          .
          .
          .
          .

       case 5 :
         if indexPath.row == 0  {cellID = "Submit" }
        cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! OrderCell


        cell.submitButton.addTarget(self, action: #selector(OrderViewController.submitNewOrder), for: .touchUpInside)

      default:
         break
      }
  return cell

   }



  func submitNewOrder() {
       //Title
      let index1:IndexPath = IndexPath(row: 0, section: 0)
      let cell1: OrderCell = tableView.cellForRow(at: index1) as! OrderCell
      print("order is \(cell1.orderTitle.text!)")

}

我确信 rowsection 是正确的!.我也厌倦了 @IBAction 的相同方法,它工作正常!有什么问题?

I am sure that row and section are right!. Also I tired same method with @IBAction and it works fine ! What is the problem ?

谢谢

推荐答案

您只需要

self.tableView(tableView, cellForRowAt: index1)

而不是

tableView.cellForRow(at: index1) as! OrderCell

它是如何工作的??

在 tableview 中,单元格被重用.仅当您滚动 tableview 并稍后点击底部某个单元格中的按钮时,您的代码才会崩溃,原因是索引路径 (0,0) 处的单元格被重用,因此 tableView 不会将单元格保留在索引路径 (0,0) 处,因此当你调用 self.tableView(tableView, cellForRowAt: index1) 它返回 nil.

In tableview, cell gets reused. Your code will crash only if you scroll your tableview and later tap on button in some cell at bottom, reason cell at index path (0,0) is reused so tableView will not keep the cell at index path (0,0) hence when you call self.tableView(tableView, cellForRowAt: index1) it returns nil.

另一方面,您可能应该做的是要求数据源委托返回单元格而不是 tableView 本身.在这种情况下,你自己的VC是数据源,所以我写了

On the other hand what you should have probably done is to ask the data source delegates to return the cell rather than the tableView itself. In this case, your own VC is data source, hence I wrote

self.tableView(tableView, cellForRowAt: index1)

这将在索引路径 (0,0) 处获得对单元格的引用,即使它不存在于 tableView 中,并将其交给 u 而不是 nil :)

This will get the reference to cell at index path (0,0) even if its not there with tableView and hand it over to u rather than nil :)

建议:

虽然上面的代码工作得很好,但我个人建议从按钮到单元格使用 IBAction,当单元格持有按钮时,在单元格中而不是在 tableViewController 中创建按钮的 IBAction 在逻辑上是有意义的.

Though the above code works absolutely fine, I personally recommend having IBAction from button to cell, As cell holds the button, it makes sense logically to create a IBAction of button in cell rather than in tableViewController.

你总是可以在你的单元格中声明一个委托并在你的 TableViewController 中实现它来通知按钮点击并让你知道哪个按钮被点击.

You can always declare a delegate in your cell and implement it in your TableViewController to inform the button tap and letting know which button was tapped.

这样的代码对于任何看过一次的人来说都是干净的.Cell 负责处理其子视图的 IBAction 并仅通知 tableViewController 在点击按钮时要做什么.另一方面,TableViewController 只是执行任务,而不必担心点击了哪个按钮.

This way code will be clean to anybody who will look at it even once. Cell is responsible for handling IBAction of its subview and informs only tableViewController what to do on tapping button. TableViewController on the other hand just performs the task and never worry about which button on which it is tapped.

let index1:IndexPath = IndexPath(row: 0, section: 0)
let cell1 = self.tableView(tableView, cellForRowAt: index1) as! OrderCell

我不会改变任何你可以使用现有代码的东西,如上所示:) 只需替换 cellForRowAt :)

I dint change anything you can use your existing code as shown above :) Simply replace cellForRowAt :)

编辑 2:

虽然上面提供的代码工作得很好,但在我们的聊天中(您可以在评论部分参考聊天)我意识到 indexPath (0,0) 处的单元格有一个 textFiled.

Though the above provided code works absolutely fine, In a chat that we had (You can refer the chat in comment section) I realised that the cell at indexPath (0,0) has a textFiled.

上述解决方案虽然适用于标签,但与 TextField 一起使用时,它返回 textField.text 为".

Above solution though works fine for label, on using it with TextField it returned the textField.text as "".

这显然是因为 cellForRowAtIndexPath 中的错误和 UITableView 的单元重用策略.

This was obviously because of mistake in cellForRowAtIndexPath and because of cell reuse strategy of UITableView.

虽然我在上面答案的建议部分提出了正式和更合适的建议,但我相信因为答案已被接受,我有责任提供也适用于 textField 的全功能代码:)

Though I have suggested formal and more proper suggestion in suggestion section of answer above, I believe because the answer is accepted, its my duty to provide fully functional code which will work with textField as well :)

一旦用户在 indexPth (0,0) 的单元格的 textField 中输入一些文本,并在 tableView 的 cellForRowAt 索引路径中正确更新 textField 文本,最简单的事情就是更新数据源.

Simplest thing to do would be update the data source once user enters some text in the textField of cell at indexPth (0,0) and update the textField text properly in cellForRowAt index path of tableView.

如果正确执行此操作,向下滚动或重复使用单元格时,textField 文本将不再返回为 "".

Doing it properly will no longer return textField text as "" on scrolling down or on cell getting reused.

我是这样做的:)

第 1 步:

使您的单元格成为 textField 委托并实现 textFieldDidEndEditing :)

Make your cell a textField delegate and implement textFieldDidEndEditing :)

class MyTableViewCell: UITableViewCell,UITextFieldDelegate {
    func textFieldDidEndEditing(_ textField: UITextField) {
       //will see implementation later
    }
}

第 2 步:

在您的自定义单元格中声明一个协议,以通知 tableViewController 使用用户文本更新其数据源 :)

Declare a protocol in your custom cell to inform the tableViewController to update its data source with user text :)

protocol updateDataSource {
    func updateDataSource(with userText : String)
}

第 3 步:

在单元格中创建一个委托 :)

Create a delegate in cell :)

var delegate : updateDataSource? = nil

第 4 步:

实现 textFieldDidEndEditing,

Implement textFieldDidEndEditing,

func textFieldDidEndEditing(_ textField: UITextField) {
    self.delegate?.updateDataSource(with: textField.text!)
}

第 5 步:

在您的 ViewController (TableViewController) 中确认委托

Confirm delegate in your ViewController (TableViewController)

extension ViewController : updateDataSource {
    func updateDataSource(with userText: String) {
        //update your data source
        //I dont have any hence am updating a instance variable in my VC
        self.userEnterredText = userText
    }
}

最后将你的 CellForRowAtIndexPath 更新为

Finally update your CellForRowAtIndexPath as

        cell.delegate = self
        if indexPath.row == 0 && self.userEnterredText != nil {
            cell.testTextField.text = self.userEnterredText!
        }
        else {
            cell.testTextField.text = ""
        }
        return cell

这将确保当您在重复使用的单元格的数据源上调用 self.tableView(tableView, cellForRowAt: index1) 时,为索引路径中的行调用单元格,并且因为您在 cellForRowAt 中的代码现在将正确填充文本字段:)

This will make sure that when you call self.tableView(tableView, cellForRowAt: index1) on a data source for a cell which is reused, to call cell for row at index path, and because of your code in cellForRowAt now your textfield will be populated properly :)

现在您仍然可以使用您的代码

Now you can still use your code

let index1:IndexPath = IndexPath(row: 0, section: 0)
let cell1: OrderCell = tableView.cellForRow(at: index1) as! OrderCell
print("order is \(cell1.orderTitle.text!)")

还有 textField :)

With textField as well :)

希望有帮助:)

这篇关于使用自定义 UITableViewCell 中的按钮获取单元格字符串的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆