Radio Button Challenge


#1

I spent far too much time fumbling around with radio buttons without success. Then I googled radio buttons and turned up the following video:

https://www.youtube.com/watch?v=NiKpjEr7br8

Thank you Obleo Beck !

The video includes a reminder that one may drag from a control in the .xib to the window containing your swift code; Xcode will automatically create the action or outlet for you, including the type of control object. I had seen this presented at WWDC a few years ago, but had forgotten about it.


#2

This is a good news / bad news followup.

The good news is that I was able to set up working radio buttons by using

[code] @IBAction func radioGroupChanged(sender: NSMatrix) {
NSLog(“radioGroupChanged(_:)”)

    var row = sender.selectedRow
    // var column = sender.selectedColumn
    
    if row == 0 {
        // show ticks
        slider.numberOfTickMarks = 11
    }
    
    if row == 1 {
        // do not show ticks
        slider.numberOfTickMarks = 0
    }
}

[/code]

just as described in the video.

The bad news:

Control-dragging from the .xib window to the .swift window failed to set up outlets or actions. Xcode complained that it was unable to resolve the class BusyBoardWindowController.

When I know more, I will update this thread.


#3

Have you double checked that your window has BusyBoardWindowController set as its class in the Identity Inspector? I usually find I’ve forgotten to set this when dragging actions/outlets fails.


#4

Thanks for asking, magnas. I will keep that in mind for future reference. Another issue is in play this time.

The first time I tried it, I had the .swift file open in one window and the .xib file open in another window. Control dragging from a UI object in the .xib window to the code pane of the .swift window resulted in the failed attempt illustrated above.

Last night, I tried again, but this time I worked within one window; the .swift source was in the left editor and the window was set to show an assistant editor for the .xib file. Control dragging from the UI object in the .xib file to the .swift source within the same window produced the desired IBOutlet or IBAction code insertion.


#5

Ah yes, that will do it too. Xcode does indeed need the ‘association’ provided by the Assistant Editor to understand what it is you are trying to do here.

You may know this already, but when you have several application window objects on the same Interface Builder window (which you will almost certainly have seen if you’ve done any iOS development), if you select a window and then click the AE button, Xcode will open the appropriate code file that represents that window.

Glad you got it sorted out.


#6

The book mentions on p.97 to ignore the Radio Group since NSMatrix is being deprecated.

It took me a while to figure it out but in the end was very simple. It needed 2 NSButtons, style Radio, with tags of 0 and 1.

[code]@IBAction func showSliderTickMarks (sender: NSButton) {

    if sender.tag == 1 {
    
        slider.numberOfTickMarks = 0
        
        
    } else {
        
        slider.numberOfTickMarks = 10
        
    }
}[/code]

#7

I originally used NSMatrix to implement the radio buttons, like tombernard, but after I finished the app, I read in the book that NSMatrix is deprecated, then the hunt through the docs began anew.

As frankm posted, and the hints to the challenge say, now you are supposed to create radio buttons from a push button(NSButton). You do that by dragging a push button onto your window, and in the Attributes inspector, in the Button section, you change the Style to Radio.

Then the question is how do you group the radio buttons? A group of radio buttons behaves in an interconnected way: when you enable one radio button in the group, the other radio buttons in the group are disabled automatically. It turns out that a group of radio buttons consists of all the radio buttons connected to the same action method. Therefore, if you want to create two groups of radio buttons, you connect all the radio buttons in one group to one action method, and you connect all the radio buttons in the other group to another action method.


#8

I still can’t see how to programmatically set which radio button is selected in this new NSMatrix-free world.

From the searching I’ve done, this should work:let showTickMarksButton = self.view.viewWithTag(2) as? NSButton showTickMarksButton.state = NSOnState

but the first line just produces this error: “Value of type ‘(NSView, stringForToolTip: NSToolTipTag, point: NSPoint, userData: UnsafeMutablePointer) -> String’ has no member ‘viewWithTag’”.

NSView has a viewWithTag method, according to Apple’s docs, so I’ve got no idea what’s going on here! How can I say “select the radio button that has tag 2”?


#9

Check out frankm’s post. In addition, there are several other threads for this chapter which contain solutions. The sender is the radio button that was clicked, so you just need to obtain the sender’s tag to identify which radio button was clicked.

You fell down a rabbit hole. Here’s what’s going on…

self.view returns a method. This one:

developer.apple.com/library/pre … t:userData:

…which looks like it was added to the NSObject class using an Objective-C technique called “categories”, which allows you to add methods to an existing class when you don’t have access to the source code for the existing class. Because NSWindowController does not have a view() method nor a view property, you end up accessing the view() method in NSObject. You must have looked at some code in an NSViewController, which does have a view property.

  1. In Swift, you can pass functions around just like you can the number 10, for example:
import Foundation

class Dog {
    func doStuff(firstNumber: Int, secondNumber: Int) -> String {
        return "hello"
    }
}

var d = Dog()
println(d.doStuff)  //=> (Function)

var myFunc: (Int, Int)->String = d.doStuff
println(myFunc(1, 2)))  //=> hello

//myFunc.viewWithTag(2)  =>  '(Int, Int) -> String' does not have a member named 'viewWithTag'
//d.doStuff.viewWithTag(2)    => '(Int, secondNumber: Int) -> String' does not have a member named 'viewWithTag'

#10

Check out frankm’s post. In addition, there are several other threads for this chapter which contain solutions. The sender is the radio button that was clicked, so you just need to obtain the sender’s tag to identify which radio button was clicked.
[/quote]

Sorry, I think I’ve misled you a bit by not being clear. I was reading which radio button is clicked without any problems, but where I was having trouble is implementing the reset button. It turns out I’d connected both radio buttons to the same outlet, thinking I had to get them by tag number.

Of course, if you connect one to a HideTicks outlet, and the other to a ShowTicks outlet, sending messages to the right one becomes much easier…

Thanks for getting me to look at the problem in a different way :smiley:


#11

Hopefully, by now you have realized that that isn’t possible. An outlet is a variable, and as such it can only ever store one value. When you connected the second radio button to the outlet, a pointer to the second radio button was assigned to the outlet variable. It’s as if you did this:

var r = "radio1" r = "radio2"

After doing that, the variable r has no knowledge about “radio1”.

As has been discussed, you actually only need an outlet variable for one of the radio buttons.