1

I am trying to create a UISwitch programatically (No IBOutlets or IBActions) and I can't seem to figure out how to get the switch to change states when pressed. I thought that ...

mySwitch.addTarget() 

... would be called every time the switch was toggled On/Off, but that doesn't seem to be the case. Can someone please explain what I am doing wrong and how to correct this.

import UIKit
import XCPlayground

let view = UIView(frame: CGRect(x: 0, y: 0, width: 320 * 0.75, height: 568 * 0.75))

view.backgroundColor = UIColor.whiteColor()
view.layer.borderColor = UIColor.grayColor().CGColor
view.layer.borderWidth = 1

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 320 * 0.75, height: 50))

label.text = "Label"
label.textAlignment = NSTextAlignment.Center

view.addSubview(label)

func switchChanged(sender: UISwitch!) {
    if sender.on == true {
        label.text = "Switch is ON"
    } else if sender.on == false {
        label.text = "Switch is OFF"
    }
}

let mySwitch = UISwitch()

mySwitch.center = view.center
mySwitch.setOn(true, animated: false)
mySwitch.onTintColor = UIColor.redColor()
mySwitch.addTarget(label, action: Selector(switchChanged(mySwitch)), forControlEvents: UIControlEvents.ValueChanged)

view.addSubview(mySwitch)

XCPlaygroundPage.currentPage.liveView = view
sMk
  • 65
  • 1
  • 8

2 Answers2

1

You need some fixes for this line:

mySwitch.addTarget(label, action: Selector(switchChanged(mySwitch)), forControlEvents: UIControlEvents.ValueChanged)

To make addTarget to work, you need an instance which responds to the action. Obviously label would not respond to switchChanged.

Enclose your action method in a class:

class MyTarget {
    @objc func switchChanged(sender: UISwitch!) {
        if sender.on == true {
            label.text = "Switch is ON"
        } else if sender.on == false {
            label.text = "Switch is OFF"
        }
    }
}

Another problem is the usage of Selector.init, if you write Selector(switchChanged(mySwitch)), Swift executes the argument switchChanged(mySwitch), and then passes the result to Selector.init. While the return type of switchChanged is Void, your code is nearly the same as writing Selector().

Try using #selector notation as far as possible. In this case, with the class introduced above, you can write it as #selector(MyTarget.switchChanged).

So, to addTarget properly, you need to change the line as:

let target = MyTarget()
mySwitch.addTarget(target, action: #selector(MyTarget.switchChanged), forControlEvents: .ValueChanged)

My Xcode is sort of stubborn and I needed to restart Xcode to see the liveview timeline, but, with these changes, I believe your code works as expected.

OOPer
  • 47,149
  • 6
  • 107
  • 142
0
mySwitch.addTarget(label, action: Selector(switchChanged(mySwitch)), forControlEvents: UIControlEvents.ValueChanged)

But it is not the label that contains the switchChanged function: it's you.

You'll have much better luck configuring this properly in an actual app project (i.e. not a playground). You'll have a view controller that can act as self and can be the target.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    Don't try to play with serious interaction like this in a playground. It's like kissing a frog: nothing happens and it annoys the frog. – matt Jul 20 '16 at 17:03