检测在tableview中按下的uibutton:Swift最佳实践

我有一个表格中的可变数目的单元格代表学生对应于他们的特定教师。 他们是一个自定义的单元格,带有一个button,触发一个新的VC的继续,提供关于其单元格的学生的详细信息。 我的问题是:

快速识别哪个button被按下的最佳做法是什么?

一旦我知道索引path,我可以确定哪些学生的信息需要传递给下一个VC。 在后面的文章中有一个很好的答案,但是我不知道如何翻译成Swift。 任何帮助将非常感激。

检测在UITableView中按下了哪个UIButton

如果你的代码允许,我build议你设置UIButton标签等于indexPath.row ,所以当它的动作被触发时,你可以拉动标签,从而在触发方法中button数据的行。 例如,在cellForRowAtIndexPath您可以设置标签:

 button.tag = indexPath.row button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside) 

然后在buttonClicked: ,你可以获取标签,从而获取行:

 func buttonClicked(sender:UIButton) { let buttonRow = sender.tag } 

否则,如果由于某种原因不利于您的代码,则将此Objective-C答案的Swift转换链接到 :

 - (void)checkButtonTapped:(id)sender { CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition]; if (indexPath != nil) { ... } } 

是:

 func checkButtonTapped(sender:AnyObject) { let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView) let indexPath = self.tableView.indexPathForRow(at: buttonPosition) if indexPath != nil { ... } } 

Swift 3.0解决scheme

 cell.btnRequest.tag = indexPath.row cell.btnRequest.addTarget(self,action:#selector(buttonClicked(sender:)), for: .touchUpInside) func buttonClicked(sender:UIButton) { let buttonRow = sender.tag } 

更新了Swift 3

如果你想要做的唯一事情就是触发一个继续,通过一个UIButton这样做是违背最佳做法的。 您可以简单地使用UIKit的内置处理程序来select一个单元格,即func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 。 你可以执行如下的操作:

创build一个自定义的UITableViewCell

 class StudentCell: UITableViewCell { // Declare properties you need for a student in a custom cell. var student: SuperSpecialStudentObject! // Other code here... } 

当你加载你的UITableView时,将数据从你的数据模型传递给单元格:

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "StudentCell", for: indexPath) as! StudentCell cell.student = superSpecialDataSource[indexPath.row] return cell } 

然后使用didSelectRow atIndexPath来检测何时已经select了一个单元格,访问该单元格和它的数据,并将该值作为parameter passing给performSegue

 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) as! StudentCell if let dataToSend = cell.student { performSegue(withIdentifier: "DestinationView", sender: dataToSend) } } 

最后在prepareForSegue

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "DestinationView" { let destination = segue.destination as! DestinationViewController if let dataToSend = sender as? SuperSpecialStudentObject { destination.student = dataToSend } } } 

或者,如果您希望他们只select一部分细胞,而不是在细胞内部的任何位置触摸,则可以在细胞上添加附件(如细节附件)(看起来像内部的“i”它),而不是使用override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath)

另一个可能的解决scheme是使用dispatch_block_t 。 如果你使用Storyboard,你首先必须在自定义的UITableViewCell类中创build一个成员variables。

 var tapBlock: dispatch_block_t? 

然后你必须创build一个IBAction并调用tapBlock

 @IBAction func didTouchButton(sender: AnyObject) { if let tapBlock = self.tapBlock { tapBlock() } } 

在你的视图控制器与UITableView你可以简单地对这样的button事件作出反应

 let cell = tableView.dequeueReusableCellWithIdentifier("YourCellIdentifier", forIndexPath: indexPath) as! YourCustomTableViewCell cell.tapBlock = { println("Button tapped") } 

但是,在块内部访问self时,必须注意不要创build保留周期。 一定要作为[weak self]来访问它。

Swift 3

@ cellForRowAt indexPath

 cell.Btn.addTarget(self, action: #selector(self.BtnAction(_:)), for: .touchUpInside) 

然后

 func BtnAction(_ sender: Any) { let btn = sender as? UIButton } 

简单而简单的方法来检测button事件并执行一些操作

 class youCell: UITableViewCell { var yourobj : (() -> Void)? = nil override func awakeFromNib() { super.awakeFromNib() } @IBAction func btnAction(sender: UIButton) { if let btnAction = self.yourobj { btnAction() } } } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = youtableview.dequeueReusableCellWithIdentifier(identifier) as? youCell cell?.selectionStyle = UITableViewCellSelectionStyle.None cell!. yourobj = { //Do whatever you want to do when the button is tapped here self.view.addSubview(self.someotherView) } return cell } 

我正在通过prepareforSegue做到这一点

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { let indexPath = self.tableView.indexPathForSelectedRow() let item = tableViewCollection[indexPath!.row].id let controller = segue.destinationViewController as? DetailVC controller?.thisItem = item } 

并在下一个控制器,我将重新加载完整的项目属性,通过知道它的ID和设置它var DetailItem在DetailVC

作为@Lyndsey和@ longbow的评论的后续,我注意到,当我在storyboard中从button到目标VC的segue时,在buttonClicked函数可以更新urlPathvariables之前调用prepareForSegue。 为了解决这个问题,我将segue从第一个VC直接设置到destinationVC,并在执行buttonClicked中的代码后以编程方式执行了segue。 也许不理想,但似乎工作。

 func buttonClicked(sender:UIButton) { let studentDic = tableData[sender.tag] as NSDictionary let studentIDforTherapyInt = studentDic["ID"] as Int studentIDforTherapy = String(studentIDforTherapyInt) urlPath = "BaseURL..."+studentIDforTherapy self.performSegueWithIdentifier("selectTherapySegue", sender: sender) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { if (segue.identifier == "selectTherapySegue") { let svc = segue.destinationViewController as SelectTherapyViewController; svc.urlPath = urlPath }