0

So I have a UITableViewCell:

enter image description here

Here is the code:

import Foundation
import UIKit

class Cell_Switch: UITableViewCell{

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var select: UISwitch!
    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    override var layoutMargins: UIEdgeInsets {
        get { return UIEdgeInsetsZero }
        set(newVal) {}
    }
    @IBAction func onSwitch(sender: AnyObject) {
        //I don't want to respond here!!!
    }
}

And here's the UITableView code:

import Foundation
import UIKit

class PreferencesInterestedDays: UIViewController,UITableViewDataSource,UITableViewDelegate{
    @IBOutlet weak var table: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        var nib = UINib(nibName: "Cell_Switch", bundle: nil)
        table.registerNib(nib, forCellReuseIdentifier: "Cell_Switch")
        table.separatorInset = UIEdgeInsetsZero

    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }





    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:Cell_Switch = self.table.dequeueReusableCellWithIdentifier("Cell_Switch") as Cell_Switch

        //what do I do here???
        //not working: cell.select.actionsForTarget(self, forControlEvent: UIControlEvents.ValueChanged)



        return cell
    }
    //this event doesn't fire!
    @IBAction func onSwitch(sender: AnyObject) {
        //doesn't work... ;(
        println("Hello!")
    }



    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        table.deselectRowAtIndexPath(indexPath, animated: false)
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 7
    }
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 44.0
    }
}

Here's what it looks like:

enter image description here

Each switch selected has a different response. I need to handle the actions (and get the row number) in the UITableView class, not in the UITableViewCell class...

What to do?

XCode 6.2, iOS 8.2

Eamorr
  • 9,872
  • 34
  • 125
  • 209

4 Answers4

1

You should delegate from Cell your action and send itself in delegate method. Like TableView does it with your view controller through dataSource and Delegate.

This article would be useful for you - https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

Pavel Gatilov
  • 2,570
  • 2
  • 18
  • 31
1

Simple solution would be

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell:Cell_Switch = self.table.dequeueReusableCellWithIdentifier("Cell_Switch") as Cell_Switch

        cell.select.addTarget(self, action: Selector("onSwitch:"), forControlEvents: UIControlEvents.ValueChanged)

        return cell
    }

    @IBAction func onSwitch(sender: AnyObject) {
        println("Hello!")
    }

Note, remove any reference of IBAction inside Cell_Switch.

Cheers.

iphonic
  • 12,615
  • 7
  • 60
  • 107
  • It works! Yes, that was nice and elegant. Need more experience at this - great to have an experienced community to help me out! – Eamorr Mar 13 '15 at 10:51
  • For good measure, I set `cell.select.tag = indexPath.row`. Now I can access the row number (`sender.tag`) inside `onSwitch(sender: AnyObject)` – Eamorr Mar 13 '15 at 10:55
  • Glad that it helped! Yes setting indexPath.row would allow you to access it more easily, to add more control, you might look into subclassing UISwitch, and add NSIndexPath as property, so you can access the whole indexPath with section, it might help in other case when section involved. – iphonic Mar 13 '15 at 11:04
  • Yes, that is probably an elegant way. I find I can access the cell inside `onSwitch(...)` with: `var cell:Cell_Switch = table.cellForRowAtIndexPath(i)! as Cell_Switch`, where `i` is `var i:NSIndexPath = NSIndexPath(forRow: sender.tag, inSection: 0)` Quick and dirty, but perhaps easier to follow for those of use who don't like subclassing gymnastics?! – Eamorr Mar 13 '15 at 11:20
1

Add target on each switch manually in your cellForRowAtIndexPath

cell.select.addTarget(self, action:"onSwitch:", forControlEvent: .ValueChanged)

Then

func onSwitch(sender: UISwitch){
    //do stuff
}
IxPaka
  • 1,990
  • 1
  • 16
  • 18
  • That got me to the right place, though I think "onSwitch:" should ready Selector("onSwitch:")? Thank you! – Eamorr Mar 13 '15 at 10:50
  • @Eamorr it doesnt require it, whatever you prefer, selectors are created from string literal and he recognizes it and creates one. Here's an excellent topic on swift selectors http://stackoverflow.com/questions/24007650/selector-in-swift – IxPaka Mar 13 '15 at 10:55
  • Thanks for the comment. It would be great to be able to use an inline block as opposed to a Selector. But I don't know if this is possible. Thanks for the link. – Eamorr Mar 13 '15 at 11:01
1

Other responses explain how to add action method. So I am going to explain how you should implement that action method.

func onSwitch(sender: UISwitch) {
    let point = tableView.convertPoint(CGPoint.zeroPoint, fromView: sender)
    if let indexPath = tableView.indexPathForRowAtPoint(point) {
        // Now you have indexPath. You now know which UISwitch sends that action.
    }
}
mustafa
  • 15,254
  • 10
  • 48
  • 57
  • That works alright. But I don't like. CGPoints? I prefer: `var indxPath:NSIndexPath = NSIndexPath(forRow: sender.tag, inSection: 0)` and `var cell:Cell_Switch = table.cellForRowAtIndexPath(indxPath)! as Cell_Switch`. Now I can manipulate any object in the cell: `cell.label.textColor = UIColor.grayColor()` changes the text color to gray. – Eamorr Mar 13 '15 at 11:30
  • I don't agree with you. Your solution spreads the logic in two places. You have to set tag inside cellForRowAtIndexPath. One might forget to do that. And hey Apple uses tag internally for uikit. Your tag value might be overriden by frameworks. – mustafa Mar 13 '15 at 12:06
  • I guess this is a bit like going to a support group where "there are no wrong answers" – Eamorr Mar 13 '15 at 15:06