[英]Swift: How can I bind an NSIndexPath to a addTarget
I have a UISwitch
in each of my dynamically created rows of which I want to bind an NSIndexPath to an addTarget selector. 我在每个动态创建的行中都有一个
UISwitch
,我想将NSIndexPath绑定到addTarget选择器。
I had considered allowing the user to tap the row to toggle the switch, but from a UX perspective it makes more sense to have the switch handle this method, therefore using didSelectRowAtIndexPath
is not an appropriate solution. 我曾考虑过允许用户点击行来切换开关,但是从UX的角度来看,让开关来处理此方法更有意义,因此使用
didSelectRowAtIndexPath
是不合适的解决方案。
When my cell is created I currently bind a selector like this: 创建单元格时,我当前绑定一个选择器,如下所示:
// Create listener for each switch
prefCell.subscribed?.addTarget(self,
action: "switchFlipped:",
forControlEvents: UIControlEvents.ValueChanged)
Which calls the corresponding method: 其中调用了相应的方法:
func switchFlipped(flipSwitch: UISwitch, indexPath: NSIndexPath) {}
Obviously this throws an error because NSIndexPath
isn't a valid reference, as I believe it will only send the buttons reference. 显然,这会引发错误,因为
NSIndexPath
不是有效的引用,因为我认为它只会发送按钮引用。 Is there any way I can bind the index path? 有什么办法可以绑定索引路径? If not, is there any way to get the current cell from the context of the
UISwitch
? 如果不是,是否有任何方法可以从
UISwitch
的上下文中获取当前单元格?
The target-action pattern does not allow arbitrary selectors. 目标动作模式不允许使用任意选择器。 You can have
f(sender:)
and f(sender:event:)
. 您可以有
f(sender:)
和f(sender:event:)
。 Both won't help you. 两者都帮不了你。 But you can use code to figure out the indexPath in the function.
但是您可以使用代码找出函数中的indexPath。
Code should be self explanatory: 代码应具有自我解释性:
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
}
}
You can try 3 approaches, as you see fit. 您可以尝试3种合适的方法。
Extensions add new functionality to an existing class, structure, or enumeration type.
扩展将新功能添加到现有的类,结构或枚举类型。 This includes the ability to extend types for which you do not have access to the original source code Apple Docs
这包括扩展您无法访问原始源代码Apple Docs的类型的能力
This should be the a good solution, not depending on a point. 这应该是一个很好的解决方案,而不是依赖于一点。 You call the superviews of the Switch and therefore calculate the index path of the cell.
您调用Switch的超级视图,并因此计算单元的索引路径。
func switchTapped(sender: UISwitch) -> NSIndexPath {
let cell = sender.superview!.superview! as UITableViewCell
return tableView.indexPathForCell(cell)!
}
This reliably works, that's why you can simply unwrap any optionals. 这可靠地起作用,这就是为什么您可以简单地展开任何可选项的原因。
Use delegation. 使用委托。
Your switch's target action should be a method in your custom UITableViewCell. 开关的目标操作应该是自定义UITableViewCell中的方法。 That custom tableviewcell should declare a protocol and the tableview should be it's delegate.
该自定义tableviewcell应该声明一个协议,而tableview应该是它的委托。 Then your tableviewcell should call its delegate method from within the switch's target function.
然后,您的tableviewcell应该从开关的target函数中调用其委托方法。
The delegate method for your tableviewcell should have a parameter in which the cell passes self
. tableviewcell的委托方法应具有一个参数,单元格将在其中传递
self
。 Then in your tableviewcontroller delegate implementation you can use indexPathForCell:
然后在tableviewcontroller委托实现中,可以使用
indexPathForCell:
UPDATE: 更新:
Here is the apple doc for swift protocols and delegates: 这是快速协议和委托的苹果文档:
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
Simply put, you need to define a protocol 简而言之,您需要定义一个协议
protocol CustomUITableViewCellDelegate {
func tableViewCellSubscribed(cell: myCustomUITableViewCell) -> Void
}
then you make your tableviewcontroller class conform to that protocol like this: 然后使您的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
}
Then your custom UITableViewCell class should have a delegate property like this: 然后,您的自定义UITableViewCell类应具有如下的委托属性:
class myCustomUITableViewCell : UITableViewCell {
var delegate : CustomUITableViewCellDelegate?
//class definition goes here
}
Finally, set the cell's delegate in tableView:cellForRowAtIndexPath:
and you're good to go. 最后,在
tableView:cellForRowAtIndexPath:
设置单元格的委托,您就可以开始了。 You just need to call your tableViewCellSubscribed:
delegate function from within the target method of your switch action. 您只需要从switch操作的target方法中调用
tableViewCellSubscribed:
委托函数。
I've used this approach in many projects, you can just add a callback to your custom cell, each time your switch changes, you can run this callback and catch it inside your table datasource implementation, below a dirt and simple example. 我在许多项目中都使用过这种方法,您只需在自定义单元格中添加一个回调,每次开关更改时,您都可以运行此回调并将其捕获到表数据源实现中,下面是一个简单的示例。
// 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)")
}
}
}
Acctually,Apple has already provide API to get the indexPath. 准确地说,苹果已经提供了获取索引路径的API。 Simply like this (in Objective-C)
就像这样(在Objective-C中)
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Far easier, you can use the tag
variable for this : 您可以轻松地使用
tag
变量:
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
...
}
From official doc : 来自官方文档:
var tag: Int { get set }
var标记:Int {获取设置}
An integer that you can use to identify view objects in your application.
可用于标识应用程序中的视图对象的整数。
The default value is 0. You can set the value of this tag and use that value to identify the view later.
默认值为0。您可以设置此标记的值,并在以后使用该值标识视图。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.