Swift:我如何将一个NSIndexPath绑定到一个addTarget

我有一个UISwitch在我的每个dynamic创build的行,我想要将一个NSIndexPath绑定到一个addTargetselect器。

我曾考虑允许用户点击该行来切换开关,但从UX的angular度来看,让交换机处理此方法更合理,因此使用didSelectRowAtIndexPath并不是一个合适的解决scheme。

当我的单元格被创build时,我现在绑定一个select器,像这样:

 // Create listener for each switch prefCell.subscribed?.addTarget(self, action: "switchFlipped:", forControlEvents: UIControlEvents.ValueChanged) 

哪个调用相应的方法:

 func switchFlipped(flipSwitch: UISwitch, indexPath: NSIndexPath) {} 

显然,这会引发错误,因为NSIndexPath不是一个有效的引用,因为我相信它只会发送button引用。 有没有什么办法可以绑定索引path? 如果没有,有什么办法从UISwitch的上下文中获取当前单元格?

目标操作模式不允许任意select器。 你可以有f(sender:)f(sender:event:) 。 两者都不会帮助你。 但是你可以使用代码来找出函数中的indexPath。

代码应该是自我解释的:

 func switchFlipped(flipSwitch: UISwitch) { let switchOriginInTableView = flipSwitch.convertPoint(CGPointZero, toView: tableView) if let indexPath = tableView.indexPathForRowAtPoint(switchOriginInTableView) { println("flipped switched at \(indexPath)") } else { // this should not happen } } 

这应该是一个很好的解决scheme,而不是一个观点。 您可以调用Switch的超级视图,从而计算单元格的索引path。

 func switchTapped(sender: UISwitch) -> NSIndexPath { let cell = sender.superview!.superview! as UITableViewCell return tableView.indexPathForCell(cell)! } 

这可靠地工作,这就是为什么你可以简单地打开任何可选项。

你可以尝试3种方法,如你所见。

  1. 创build一个自定义的UISwitch类,并为其添加一个NSIndexPath属性。 当您收到通知时,请向您的自定义类键入cast并访问NSIndexPath。
  2. 创build一个自定义的UITableViewCell类,并保存NSIndexPath。 当你得到UISwitch的通知,得到它的超级视图,看看哪一个是你的customUITableViewCell实例,并获得属性。
  3. 如果你只有一个部分,这意味着所有你需要担心的是行。 将UISwitch标签设置为行号,并在交换机翻转时进行访问。
  4. 最技术的Savy解决scheme使用Swift的扩展。

扩展为现有的类,结构或枚举types添加新的function。 这包括扩展您无法访问原始源代码Apple文档的types

使用委派。

你的开关的目标行动应该是你的自定义UITableViewCell中的一个方法。 该自定义tableviewcell应该声明一个协议和tableview应该是委托。 然后你的tableviewcell应该从交换机的目标函数中调用它的委托方法。

你的tableviewcell的委托方法应该有一个参数,在这个参数中单元格通过self 。 然后在你的tableviewcontroller委托实现中,你可以使用indexPathForCell:

更新:

这里是swift协议和委托的苹果文档:

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

简而言之,您需要定义一个协议

 protocol CustomUITableViewCellDelegate { func tableViewCellSubscribed(cell: myCustomUITableViewCell) -> Void } 

那么你让你的tableviewcontroller类符合这样的协议:

 class myTableViewController: UITableViewController, CustomUITableViewCellDelegate { func tableViewCellSubscribed(cell: myCustomUITableViewCell) -> Void { //this is where you handle whatever operations you want to do regarding the switch being valuechanged } // class definition goes here } 

那么你的自定义UITableViewCell类应该有这样的委托属性:

 class myCustomUITableViewCell : UITableViewCell { var delegate : CustomUITableViewCellDelegate? //class definition goes here } 

最后,在tableView:cellForRowAtIndexPath:设置单元格的委托tableView:cellForRowAtIndexPath:你很好。 你只需要在你的switch动作的目标方法内调用你的tableViewCellSubscribed: delegate函数。

我已经在很多项目中使用了这种方法,只需在自定义单元格中添加一个callback函数,每当交换机发生变化时,都可以运行这个callback函数,并在表格数据源实现中捕获它,在一个简单的例子下面。

1.创build一个UITableViewCell自定义类

 // An example of custom UITableViewCell class class CustomCell:UITableViewCell { required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } var onSwitchChange:() -> Void? } class TableDataSource:UITableViewDataSource { func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell:CustomCell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as CustomCell cell.onSwitchChange = { NSLog("Table: \(tableView) Cell:\(cell) Index Path: \(indexPath)") } } } 

实际上,苹果已经提供了获取indexPath的API。 就像这样(在Objective-C中)

NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

更容易,你可以使用tagvariables为:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { ... cell.mySwitch.tag = indexPath.item cell.mySwitch.addTarget(self, action: #selector(switchChanged), for: UIControlEvents.valueChanged) ... } func switchChanged(mySwitch: UISwitch) { let indexPathItem = mySwitch.tag ... } 

从官方文档:

var tag:Int {get set}

一个整数,您可以用来标识应用程序中的视图对象。

默认值为0.您可以设置此标记的值,并使用该值稍后标识视图。