This article is about my first challenge whilst creating an OS X app using the latest Xcode (beta 7), Swift, and trying to create an action from a NSToolbarItem to modify views in the NSViewController that is attached to the NSWindowController of the app.
I love the fact that apple has done a good job to enable developers to create OS X applications using storyboards. Storyboards are a great feature that helps you visualise the routes your app can take from screen to screen, pop up windows and segue ways that link to other view controllers, etc. They are also great to help you move your code out of your main window and place it in separate controllers. If you have streamed or attended the WWDC14 conference you may have seen how amazingly they showed the usefulness of storyboards with an example when they created Pages in Session 212: Storyboards and controllers in OS X. With all these benefits I decided to go ahead and create my first application — using storyboards of course!
As I set everything up and kept learning about all what I can see on my screen (the controllers, windows, attributes, inspectors, etc), I came across a very particular situation: I want my application to have a toolbar, very much like the one in the new Photos app in Yosemite, and I want a button in the toolbar that allows the user to show and hide a split view. But before I started with the real thing, I wanted to make things simpler and set the goal to just:
Change some text in the main view controller when the user pressed the button from the toolbar.
Just setting this as your first main goal sounds quite simple and straight forward, doesn’t it? Well, as it turned out, it isn’t!… I’m just a beginner at the moment, but if you are experienced I hope you can find some sense in the things I’ve tried in order to achieve this goal: 1. I created a project in Xcode (I’m using Xcode 7 beta to use the newest features to date including Swift2, and hopefully UI testing in days to come…). I created an OS X Cocoa project with swift and storyboards, so this is what I got:
So far so good. My application started with the new relationship between NSWindowController and a separate NSViewController, which is something developers that don’t use storyboards, may find a bit awkward. 2. As a beginner I followed the instructions in this YouTube video (which happens to be one of the very few things you can find about NSToolbar in OS X!): Cocoa Programming L17 — NSToolbar. This video shows how to work with NSToolbar when you don’t use storyboards so some things are quite different (hence why I’m writing this article!). So, I simply added my NSToolbar from the Object library to the NSWindowController, and then expanded the toolbar and dragged a Textured Round Button (NSButton) from the Object library to the NSToolbar. I finally placed the button in the section of default toolbar items so they user could see it from the start.
3. On the Main view controller I added a label (NSTextField), filled horizontally and added missing constraints (Centre X and Centre Y):
At this stage I already had all the views, and controllers I needed, to finish my goal. So I found myself with the following hierarchy:
Implementation and linking
This is the tricky part. Normally I would think that to achieve my goal I would only need to:
- Create a new file to declare specific behaviours for my NSViewController (it’s actually already created for me for this example so I didn’t need to do this step).
- Link the label to the new file using an outlet (IBOutlet) so I can update its text.
- Create an action (IBAction) that once triggered, it will update the label’s text.
- As a final step, link the button to the action.
The first three are quite straight forward. This is the way things would look like after doing them:
After some research I haven’t quite found yet a good way to implement the last bit (linking the button). I found the following:
- Apple has done a good job at documenting everything about NSToolbar… but only for using Objective-C and manual .xib files (not Storyboards). The steps at the end of the article: Creating a Toolbar in Interface Builder -> Setting the Target, Action, and Toolbar Delegate are not updated to reflect the fact that:
- NSWindowController is a complete separate entity from NSViewController and you can’t just link them like they say!
- The YouTube video I shared in this article explains everything as it should be done without storyboards (similarly to the Apple documentation). So again, this doesn’t help much.
- The community in StackOverflow have found some workarounds to the issue, but all of them seem a bit dodgy compared to what apple would do to achieve this goal. Some developers have suggested (1) making a connection using the first responder, others suggest (2) creating an instance of the view controller in the window controller and changing its properties from there. Others have suggested that (3) you instantiate an object at each other’s scene to read from it.
I’m very confused on what to do at this point but if you follow my article, I will update it in the future and share my experience on what I did to solve the problem. For now, I have created a question in StackOverflow with enough detail, so perhaps someone can help me find the right answer to this problem. You can follow my question here. Feel free to leave comments and share my post. I would really appreciate if you can answer my question, or know someone that can!