NSSegmentedControl and Core Data.

It’s not possible to directly hook up an NSSegmentedControl (or NSSegmentedCell) to a Core Data controlled NSArrayController (or any, for that instance). I wanted to be able to use one of these controllers to allow the user to select one, many or all items from the array.

To define the behaviour a little bit more: You can select the first item in the control (which will be called “All”), and it will select or deselect all of the other items, depending on what it’s state becomes. If you click on another segment, then it will toggle the selection of that segment. If all segments are ON after pressing a segment, then the first segment must also display ON, otherwise it will be OFF.

I did it by creating a new class: SegmentController. (I know, I should put on a prefix…)

SegmentController has two required IBOutlet variables, which refer to the NSSegmentedControl, the NSArrayController, and a property NSMutableIndexSet, which stores, sets and gets the selection indexes (I think this should be indices, but I’ll stick with Apple’s convention). I also have a sortDescriptors array, so that this object can sort the array controller.

There are a couple of limitations, which I might look at how I deal with - for instance, the NSSegmentedControl must have exactly one more segment than the NSArrayController has items. I’m using it to select one or more days, and this number doesn’t change. It should be possible to dynamically create the right number of segments, and populate them with values (I even have a readonly field called shortName set aside in my Day objects for this), but at awakeFromNib the NSArrayController is still empty, and I can’t figure out a nice neat way to force a fetch.

Hooking up the elements in Interface builder is easy. Create the NSArrayController, and set that up however you need to. Do the same with the NSSegmentedControl - at this stage you’ll need to put values in each of the segments. Now, create a new instance of SegmentController (you might need to add the class files to your XCode project first). Connect the two outlets up to the required objects.

Now, in the Bindings Inspector, connect up you’ll want to make the Selection Indexes parameter point to the selectionIndexes model key of your Segment Controller object.

Finally, make the selector of the NSSegmentedControl point to the selectSegment: action of the Segment Controller.

I did notice a slight delay between deselecting one segment and the “All” segment deselecting. A simple optimisation - moving the call to segmentCount out of the loop test and into a local variable made it much smoother.

That should probably do it. It might need a bit of tweaking. You should be able to have multiple instances of this in your project, if it is required. It’s been designed that you’ll need a seperate one for each Segmented Control, as it refers to the objects it is connected to, rather than the sender of the message.

My source code is here: SegmentController.zip

NSScrollView copiesOnScoll Slowdown

I have a custom class, called MultiMatrix, which is basically an NSMatrix that has header rows and columns. Selecting a header row or column will select the whole row/column, and selecting the top-left cell will select the whole table. These header cells will also automatically select themselves if their whole row/column/table is selected.

Because I dynamically update the size of the matrix according to some data elsewhere in my program, I needed to embed it into an NSScrollView, so that when the size exceeds the normal size, then users can scroll to select cells.

I did this, and I was having huge slowdowns. I could select cells alright, but selecting a header cell meant about a one second delay.

Solution: turn off the NSScrollView’s copiesOnScroll.

Even though I wasn’t scrolling, for some reason this was causing big performance issues.

I suspect it’s making my custom matrix class do something lots of times, or perhaps it’s related to the controller and the bindings I have set up. Regardless, unchecking the Copies On Scroll box in IB fixed it.

NSSegmentedControl selecting NSTabView

I discovered, quite by accident the other day, that it is possible to use an NSSegmentedControl to control which Tab of an NSTabView is displayed. Here is how to do it.

First of all, it is much easier to change the selected tab if you leave the tabs on to begin with. So, I would suggest building all of the NSTabView’s tabs first. I’ve done five, each with a different control.

View1.png View2.png

Now, you can alter the NSTabView so it doesn’t show the Tabs:

View1Tabless.png TabViewInspector.png

You can now add the NSSegmentedControl, and style it as you wish. I really like the Small Square styling.


Now to hook up the connection. There is an outlet on NSTabView called takeSelectedTabViewFromSender:, which can be hooked up to an NSSegmentedControl.


You will need to ensure that your initially selected cell and view are the same index, which prohibits having it save the value between runs (or you might be able to, if you know more than me).

#1 Fix for Twitterific

It annoys me that when I click off the Twitterrific window, it doesn’t auto-hide. There doesn’t seem to be a setting to make this happen.

Luckily, you can fix this with a quick edit to the MainMenu.nib file.

(This requires you have InterfaceBuilder, and therefore the developer tools installed.)

View the contents of the Twitterrific.app package, and navigate to the Resources/English.lproj directory, and open up MainMenu.nib. Find the Tweet Window, and change it’s properties to “Hide on Deactivate”.

Save the nib, and restart Twitterrific. Bingo, clicking off the window auto-hides.

Using Self-signed Certificates with WSMethodInvocationRef

I’ve played quite a lot with the Cocoa methods for doing WebServices: lots of people whinge about how little support is given to SOAP from Cocoa, but I actually think it’s not too bad.

To create a SOAP request is quite complicated, but it’s easy to abstract most of this out.

The first step is to create the WSMethodInvocationRef, using WSMethodInvocationCreate. This takes three arguments, one of which is the endpoint URL, which for most cases will be the same across all of your application’s requests. The second is the method name, and the third is the protocol you are using.

You then just need to set the parameters, namespace, headers and so on. This takes care of generating all of the SOAP Envelope stuff, and you can then just use this object to pass to WSMethodInvocationInvoke. This returns a CFDictionaryRef, which is toll-free bridged with an NSDictionary, and gives you status information, as well as results. Notably, this dictionary contains one with the key “/Result”, which contains another dictionary with all of the result data - and this is the cool part - it has already been converted back from XML into whatever structure it represents!

I’ve wrapped this up a little further into some classes - they are still a little under construction, but I’ll release them on bitbucket or something when I’ve cleaned them up a little. I may even make it into a Framework. Which I have been meaning to learn how to do.