使用自定义UITableViewCell中的button获取单元格string的问题

我想获取单元格的string使用自定义UITableViewCell的button。但是,当我点击button应用程序崩溃,由于此错误: fatal error: unexpectedly found nil while unwrapping an Optional value

我尝试print一些东西,它的工作原理!但是当我试图让其他单元格的应用程序崩溃。 这是我的代码:

  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累了同样的方法,它工作正常! 问题是什么 ?

谢谢

所有你需要的是,

 self.tableView(tableView, cellForRowAt: index1) 

而不是

 tableView.cellForRow(at: index1) as! OrderCell 

怎么运行的 ??

在tableview中,单元格被重用。 你的代码会崩溃,只有当你滚动你的tableview,然后点击底部的一些单元格中的button,原因单元格在索引path(0,0)被重用,所以tableView不会保持单元格在索引path(0,0),因此当你调用self.tableView(tableView, cellForRowAt: index1)它返回nil。

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

 self.tableView(tableView, cellForRowAt: index1) 

这将得到索引path(0,0)的单元格的引用,即使它不在那里与tableView交给你,而不是零:)

build议:

虽然上面的代码工作得很好,但我个人build议从button到单元格有IBAction,当单元格保存button时,在单元格而不是tableViewController中创buildbutton的IBAction是合理的。

你总是可以在你的单元格中声明一个委托并在你的TableViewController中实现它来通知button点击,并且知道点击了哪个button。

任何人只要看一遍,这样的代码都是干净的。 Cell负责处理其子视图的IBAction,并只通知tableViewController在点击button上做什么。 另一方面,TableViewController只是执行任务,而不用担心在哪个button上点击它。

编辑:

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

我dint更改任何你可以使用你现有的代码,如上所示:)只需replacecellForRowAt 🙂

编辑2:

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

上面的解决scheme,虽然工作正常的标签,使用TextField它将textField.text返回为“”。

这显然是因为cellForRowAtIndexPath中的错误以及UITableView的单元重用策略。

虽然我在上面的答案的build议部分中提出了正式和更合适的build议,但我相信因为答案被接受了,所以我的职责是提供全function的代码,这个代码将和textField一起工作:)

最简单的做法是更新数据源,一旦用户在indexPth(0,0)的单元格textField中input一些文本,并在tableView的cellForRowAt索引path中正确更新textField文本。

正确地做,将不再返回textField文本作为“”向下滚动或单元格获得重用。

这是我做的:)

步骤1:

使您的单元格textField委托,并实现textFieldDidEndEditing 🙂

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

第2步 :

在你的自定义单元中声明一个协议来通知tableViewController用用户文本更新它的数据源:)

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

第3步:

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

 var delegate : updateDataSource? = nil 

步骤4 :

实现textFieldDidEndEditing,

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

第5步:

在您的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为

  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)时,要在索引path处调用行的单元格,并且由于cellForRowAt中的代码,现在您的文本字段将为正确填充:)

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

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

与textField以及:)

希望能帮助到你 :)