Kodeco Forums

macOS Development for Beginners: Part 3

In this macOS Development tutorial for beginners, learn how to create your first macOS app: a magic 8-ball app!


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/729-macos-development-for-beginners-part-3

Good tutorial. Going to use this to get my daughter started in programming on macOS. Just 1 issue I found. The short description (at the top of this and on the article listing) says itā€™s to make a magic 8-ball when itā€™s actually an egg timer.

Thanks Richard, I am working on getting the description changed. It refers to an earlier version of this tutorial.

Good luck to your daughter and please tell her to ask if there is anything she is unclear about.

Will do. I did find the 8-Ball one and weā€™re also going to do that one together after the initial.

This tutorial was supposed to replace the 8-Ball one, updated for Swift 3 & Xcode 8.

For your next tutorial, I recommend https://www.raywenderlich.com/149295/macos-controls-tutorial-part-12 which goes into more details about a lot of the available UI elements.

Great tutorial.
One question: Every time I click on ā€œPreferencesā€ even if the Preferences dialog is already open, I get an additional Preferences dialog.
Did I overlook it or is it not in the scope of the tutorial?

Regards
Niels

Hi Niels,

I probably should have mentioned this, but the fix is easy.

In Main.storyboard, select the Window Controller that presents the Prefs View Controller. In the Attributes Inspector, change its Presentation to Single which will only allow one Preferences window to be open.

Nice tutorial series! Thank you! :+1:

Very good tutorial, thanks for that. Of course there are a lot of open questions, but itā€™s definitely a good startingpoint.

I might have discovered a small bug: In ViewController.swift, I replaced all 3 occurences of 360 with prefs.selectedTime, but within func imageToDisplay() this should in my opinion be set to eggTimer.duration.

Otherwise there is a strange behaviour: You have a long running timer (e.g.25 min), start it and while itā€™s running, you change prefs to a short timer (e.g. 1 min). When you hit cancel in the modal dialog, percentageComplete will still be calculated based on the new prefs. So while there are in fact 24 minutes to go, the ā€œegg colorā€ is then calculated based on the new preference, so it getā€™s red immediately.

I think that by the time you finish working through the tutorial, the app will reset a running timer when you change the duration, so the display will go back to the starting display.

Sarah @sarah,

Great tutorial. I was moving right or wrong and came across a problem. It seems that the statement:

NSImage(named: stoppedImageName)

no longer works. I get error message: Cannot convert value of type ā€˜Stringā€™ to expected argument type ā€˜NSImage.Nameā€™. I am running XCode Version 9.0 beta (9M136h).

Bob

I finally got around this by using the following statement:

return NSImage(named: NSImage.Name(rawValue: stoppedImageName))

I had to change the following line of code as well:

if let appDel = NSApplication.shared().delegate as? AppDelegate {
            appDel.enableMenus(start: enableStart, stop: enableStop, reset: enableReset)
        }

had to be changed to:

if let appDel = NSApplication.shared.delegate as? AppDelegate {
            appDel.enableMenus(start: enableStart, stop: enableStop, reset: enableReset)
        }

Hope this helpsā€¦

Iā€™ve noticed an odd behavior to the app: when the timer is counting down, if you access the menu the display stops until you mouse-click in the window where the display jumps to current-time. Is this something new with XCode 9.0/Swift 4, or does this occur in Swift 3 as well?

Bob

Hi Bob,

When a menu is down it is like having a modal dialog open and the Timer actions do not get called. When you make a menu choice or close the menu, the display will update.

One of the appā€™s windows should be active anyway when you are selecting from the menus, so it should not be necessary to click in the window again.

This happens in Swift 3 & 4.

I will update the tutorial to Swift 4 once it is out of beta. While it is still a moving target, I will leave it as is for Swift 3.

But thanks for the heads up about the parts that will need fixing.

Sarah, thanks for responding.

Hi Sarah,

I have been playing with the EggTimer App to see if I could continue the timer when the preference content was open. I converted the dialog window to a sheet by deleting the second window controller, adding a button to the EggTimerā€™s view controller content, and cntrl-drag the button to the preference view controller content. I still use the PrefViewController to process the preference options. To get the preference menu item to work, I created an IBAction in ViewController, named the seque connecting the two content views (EggTimer & Preference) and used the following command to complete the link:

@IBAction func preferenceMenuItemSelected(_ sender: Any) {
self.performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: ā€œprefSequeā€), sender: self)

}

Using this code the timer continues to fire when the sheet is displayed. You are correct that the timer still doesnā€™t get called when the menu is selected, but I was wondering if there is another way.

So, my long winded questions are: Is this technique for doing preferences ok, or does it violate best practices? And, is there another way to continue to call the timer when the menu is selected?

Bob

I think this is a perfectly acceptable way of doing things.

I might still keep the second Window Controller and create the segue to it instead of directly to the view controller. This is so you have more control over how the Preferences window is displayed, but it should still get around the menu-blocking issue.

Regards,
Sarah

@sarah Thanks for the tutorial. Iā€™ve been working on my own project and your series has been invaluable. Itā€™s my first Mac app and I really enjoy it, wish I would have started earlier.

This was a great series and exactly what I needed to get started with my first Mac app. So thank you!

One thing I noticed that should (maybe?) be changed. Shouldnā€™t delegates normally be weak vars to ensure they release memory properly? i guess as long as you manually nil out the Timer itā€™s fine.

I guess it really should be weak, but in this case, the app is always going to have an EggTimer instance and so it will never be released which is where a leak could occur.

But you are right and it is probably best to get into the habit of making delegates weak.