Mikael Konutgan

OS X Tutorial: A Menu Bar App

My post about making Simple Menu Bar Apps for OS X has been one of the most viewed pages on my site since I wrote it back almost 2 years ago. It was never a complete tutorial to begin with, more of a few tips and tricks of how to do it well and a link to an example app I had written.

Since then, Apple has released Yosemite, which changes the way the menu bar APIs work and makes showing custom views in a popover in place of a simple menu much easier. Also, as you probbaly know, we have a brand new language to write OS X apps with.

My tutorial was due an update, so I pitched the idea of writing a complete menu bar app for OS X tutorial to Ray, for whom I have been updating tutorials for iOS 8 and Swift and he liked it.

Check out the tutorial at raywenderlich.com. I show you how to build a complete menu bar app that shows inspiratinal quotes in a popover.


Modeling Shapes in Swift

A few friends and I were talking about functional programming vs. object oriented programming the other day and I decided to illustrate the concepts in Swift using a simple and classic example. Consider a shape model. There will be different shapes and we want to calculate each shape's perimeter and area.

An object oriented programmer might write it like this:

let pi = 3.14159265358979323846264338327950288

class Shape {
    func perimeter() -> Double {
        return 0.0
    }

    func area() -> Double {
        return 0.0
    }
}

class Circle: Shape {
    let radius: Double

    init(radius: Double) {
        self.radius = radius
    }

    override func perimeter() -> Double {
        return 2.0 * pi * radius
    }

    override func area() -> Double {
        return pi * radius * radius
    }
}

class Rect: Shape {
    let width: Double
    let height: Double

    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }

    override func perimeter() -> Double {
        return 2.0 * (width + height)
    }

    override func area() -> Double {
        return width * height
    }
}

And then use it like so:

let shapes = [
    Circle(radius: 1.0),
    Rect(width: 3.0, height: 4.0)
]

let perimeters = shapes.map { shape in shape.perimeter() }
let areas = shapes.map { shape in shape.area() }

Shape is an abstract superclass which declares the methods that subclasses should override.

To add a new shape, we simply create a new class and then implement each of Shape's methods. To add a new computation, we first add a method to Shape, returning a default value, followed by implementing the method appropriately in each subclass.

In Swift, a very similar solution would be to use a protocol instead of an abstract superclass. This has the advantage that any existing class can be made into a shape and we can mix and match classes and structs if need arises. What we lose is the ability to have methods in the superclass that use the subclass methods to perform additional work, as Swift protocols cannot have default implementations.

let pi = 3.14159265358979323846264338327950288

protocol Shape {
    func surface() -> Double
    func area() -> Double
}

class Circle: Shape {
    let radius: Double

    init(radius: Double) {
        self.radius = radius
    }

    func surface() -> Double {
        return 2.0 * pi * radius
    }

    func area() -> Double {
        return pi * radius * radius
    }
}

class Rect: Shape {
    let width: Double
    let height: Double

    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }

    func surface() -> Double {
        return 2.0 * (width + height)
    }

    func area() -> Double {
        return width * height
    }
}

A functional programmer might solve the problem like this:

let pi = 3.14159265358979323846264338327950288

enum Shape {
    case Circle(Double)
    case Rect(Double, Double)
}

func perimeter(shape: Shape) -> Double {
    switch shape {
    case let .Circle(r):
        return 2.0 * pi * r
    case let .Rect(width, height):
        return 2.0 * (width + height)
    }
}

func area(shape: Shape) -> Double {
    switch shape {
    case let .Circle(r):
        return pi * r * r
    case let .Rect(width, height):
        return width * height
    }
}

And then use the constructs like so:

let shapes = [
    Shape.Circle(1.0),
    Shape.Rect(3.0, 4.0)
]

let perimeters = shapes.map { shape in perimeter(shape) }
let areas = shapes.map { shape in area(shape) }

Here, we use an algebraic data type. Then in each function, we pattern match on the shape, returning the appropriate value.

In this case, to add a new shape, we simply add a new case to the Shape enum and then add a case for that new shape to each function. To add a new computation, we add a new function, pattern match on the shape and return the appropriate value.

Additionally, Swift allows enum's to have methods so it gives us the convenience of defining all the computations in a single context while keeping the code in a functional style.

let pi = 3.14159265358979323846264338327950288

enum Shape {
    case Circle(Double)
    case Rect(Double, Double)

    func perimeter() -> Double {
        switch self {
        case let Circle(r):
            return 2.0 * pi * r
        case let Rect(width, height):
            return 2.0 * (width + height)
        }
    }

    func area() -> Double {
        switch self {
        case let Circle(r):
            return pi * r * r
        case let Rect(width, height):
            return width * height
        }
    }
}

This is basically the same as the functional example, but instead of having top level functions, all computations are nicely inside the Shape enum. And the usage is exactly the same as the object oriented case:

let shapes = [
    Shape.Circle(1.0),
    Shape.Rect(3.0, 4.0)
]

let perimeters = shapes.map { shape in shape.perimeter() }
let areas = shapes.map { shape in shape.area() }

The main disadvantage of this setup is that it's now very difficult and inelegant to have specific functions that only operate on a specific shape. In the object-oriented style, we could just add methods to the Circle class for example, and in the functional case we could write functions that take a Circle.

Like most things there is no correct answer here. It's really nice that Swift provides many options.


Swift Type Conversions

In Swift, the native String, Array and Dictionary types are implicitly bridged to the Foundation classes NSString, NSArray and NSDictionary. In practice, this means that any Cocoa API we call that takes a Foundation class can take the corresponding Swift type (I don't say class here, because in Swift, String, Array and Dictionary are structs).

It turns out that like many other things in Swift, this isn't some language magic that only Apple gets to use. We can also build such implicit bridges, thanks to an undocumented Swift feature: The __conversion function.

Let's say we want to build a Point structure. We will be using it in a context that doesn't involve Core Graphics, Sprite Kit or a similar framework that already uses CGPoint. In addition, we want to build the struct in a modern way using new features idioms like generics and tuples. But, we also want to use our new struct with Core Graphics APIs sometimes so we can take advantage of all the convenience functions we implemented (This is a contrived example, because points are so simple, but bear with me).

struct Point {
    let x: Double, y: Double
}

Let's define the implicit bridging in an extension:

extension Point {
    func __conversion() -> CGPoint {
        return CGPoint(x: x, y: y)
    }
}

Now it's possible to pass a Point to any method or function that takes a CGPoint.

let p = Point(x: 1.0, y: 1.0)
CGPointApplyAffineTransform(p, CGAffineTransformMakeRotation(M_PI))

The extension can even be defined in a different file in the context where we want to use Point as a CGPoint.

We can also overload the __conversion function and define many different conversions. Here's one that destructures Point into a (Double, Double) tuple.

extension Point {
    func __conversion() -> (Double, Double) {
        return (x, y)
    }
}

Now this works!

let (x, y) = p

I believe this will come in handy, especially when we start writing more and more Swift and we want to isolate non-Swift and/or legacy API calls and classes.


BOOL

I recently bought the NSHipster book and was rereading BOOL / bool / Boolean / NSCFBoolean and noticed the part where Mattt explains how comparing with YES can be dangerous, because BOOL is a typedef of signed char. I remembered that on 64-bit devices BOOL is actually a typedef of bool, the native (as of C99) boolean type.

The intersting thing is that the native bool type is safe, safe in the sence that a variable typed as bool can only ever have the values 0 or 1. So

BOOL value = 5;
NSLog(@"%d", value);

prints 5 on all iPhone's except for the iPhone 5s, where it prints 1.

Also e.g. (BOOL)5 is 1 on 64-bit devices, getting rid of the awkward !! pattern to safely cast other types into booleans.

Even so, you probably shouldn't compare boolean expressions with YES, but at least you will get the expected result on 64-bit devices going forward, as functions or methods returning BOOL will always return 0 or 1.


Making Simple Menu Bar Apps for OS X

Update 05 May 2015: I have written an updated, more in depth tutorial on how to make a menu bar app on OS X 10.10 Yosemite and with Swift.

It's pretty easy to make a simple menu bar app on OS X. The main thing you need to do is to create an NSStatusItem instance variable in your app delegate. To do this, you ask [NSStatusBar systemStatusBar] to create one for you, providing a length. In almost every case you will want to use NSVariableStatusItemLength instead of some fixed float value. Once you have an NSStatusItem, you can configure it using it's properties. I used some of the most relevant ones below:

@interface KMAppDelegate : NSObject <NSApplicationDelegate>

@property (strong, nonatomic) NSStatusItem *statusItem;
    
@end
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];

// The text that will be shown in the menu bar
_statusItem.title = @"";

// The image that will be shown in the menu bar, a 16x16 black png works best
_statusItem.image = [NSImage imageNamed:@"feedbin-logo"];

// The highlighted image, use a white version of the normal image
_statusItem.alternateImage = [NSImage imageNamed:@"feedbin-logo-alt"];

// The image gets a blue background when the item is selected
_statusItem.highlightMode = YES;

Next, you will want something to happen when the status item is clicked. You have a few options here: You can have a menu be shown, you can configure a target-action pair and use the status item like a button or you can have a custom view be shown. See the documentation for all the details. Here, we use a simple menu and attach it to the status item.

NSMenu *menu = [[NSMenu alloc] init];
[menu addItemWithTitle:@"Open Feedbin" action:@selector(openFeedbin:) keyEquivalent:@""];
[menu addItemWithTitle:@"Refresh" action:@selector(getUnreadEntries:) keyEquivalent:@""];

if ([[[KMFeedbinCredentialStorage sharedCredentialStorage] credential] hasPassword]) {
    [menu addItemWithTitle:@"Log Out" action:@selector(logOut:) keyEquivalent:@""];
} else {
    [menu addItemWithTitle:@"Log In" action:@selector(logIn:) keyEquivalent:@""];
}

[menu addItem:[NSMenuItem separatorItem]]; // A thin grey line
[menu addItemWithTitle:@"Quit Feedbin Notifier" action:@selector(terminate:) keyEquivalent:@""];
_statusItem.menu = menu;

The rest is all up to you. You can pretty much set up a simple app that connects to a web service and shows some information in an hour or two.

Note that you will probably want to have the app not show up in the dock. To do this you need to set the LSUIElement key to YES in your Info.plist configuration file. You should see Application is agent (UIElement) set to YES if you have done it correctly.

The sample code I used is an app I wrote to show me the number of unread RSS items in my Feedbin account. You can check it out on GithHub. It pretty much creates a status item in the app delegate and then refreshes the unread count every two minutes using an NSTimer. Before that, it asks the user to log in and then saves the user's password in the system keychain, so there are a few helper classes in addition to the app delegate. The whole app is comprised of a mere 202 lines of Objective-C code according to cloc.