Navigation
Wednesday
Jun042014

Switfly build a Mac app

Curious about Swift, I went ahead and translated Matt Gallagher’s example from Objective-C to Swift. If you stick this in a Playground file it will launch a minimal Mac app. Or you create a simple text file and chmod +x it for direct execution from the command line.
#! /usr/bin/swift -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk

import Cocoa

var app = NSApplication.sharedApplication()
app.setActivationPolicy(.Regular)

var menuBar = NSMenu()
var appMenuItem = NSMenuItem()
menuBar.addItem(appMenuItem)
app.mainMenu = menuBar

var appMenu = NSMenu()
var appName = NSProcessInfo.processInfo().processName
var quitTitle = "Quit \(appName)"
var quitMenuItem = NSMenuItem(
    title: quitTitle,
    action: Selector("terminate:"),
    keyEquivalent: "q"
)
appMenu.addItem(quitMenuItem)

appMenuItem.submenu = appMenu

var window = NSWindow(
    contentRect: CGRect(x: 0, y: 0, width: 200, height: 200),
    styleMask: NSTitledWindowMask,
    backing: NSBackingStoreType.Buffered,
    defer: false
)

window.cascadeTopLeftFromPoint(NSPoint(x: 20, y: 20))
window.title = appName
window.makeKeyAndOrderFront(nil)
app.activateIgnoringOtherApps(true)
app.run()
Wednesday
Aug212013

Work can be frustrating sometimes

Wednesday
Oct242012

Location-aware passcode settings

Are you on the fence what the passcode setting should be on your iOS device? Are you worried that anyone could access all your data if you left it somewhere yet at the same time annoyed by having to type in your passcode all the time?

I know I am. I use my phone so frequently that a five minute passcode setting actually rarely kicks in. My iPad on the other hand I don’t pick up as often and therefore I would have to enter the passcode pretty much every time. Which is why I don’t use one.

This came back to bite me a few weeks ago when I left my iPad on the cross-trainer in the gym. When I noticed my iPad was missing I wished I had at least set a passcode to protect its contents. Thinking about why I hadn’t, it occurred to me how I could have had the best of both worlds: no passcode while at home or at other places I consider “safe” and a passcode everywhere else.

iOS should simply allow you to define location specific passcode settings. You should be able to define a default which applies everywhere and then one or more regions that are exceptions. This would allow you to define a basic safe setting with a passcode and then other areas where you’re more liberal. You could even have passcode settings of different complexity depending on where you are. No passcode at your home, a complex one abroad, and a simple one everywhere else.

Below you‘ll find an illustration of what the setup for this could look like.

Sunday
Aug122012

Unit testing asynchronous code

Grand Central Dispatch and blocks have made it very easy to send blocks of code off to the background for execution and since it is so much easier, asynchronous code is much more common.

All this is a blessing – except when it comes to unit testing. To test the result of an asynchronous task, you need to force it back to “synchronicity”, so to speak. Unfortunately, Xcode’s built-in testing framework SenTestingKit does not provide any help in this regard. All its test macros like STAssertEquals assume values to be returned synchronously, leaving it up to you to provide them from asynchronous tasks.

GHUnit, on the other hand, does have a mechanism to test asynchronous tasks. However, its setup is a little more complicated than simply adding the built-in SenTestingKit. Unless you need GHUnit for some of its other features, STK is therefore usually the best way to get started with unit testing in Xcode.

To allow for asynchronous testing with SenTestKit, I’ve added a category to SenTestCase that is based on GHUnit’s asynchronous test. It is available as part of a sample project on github.

A test of an asynchronous task using the added method waitWithTimeout:forSuccessInBlock: looks like this:

- (void)test_completion
{
  Downloader *dl = [[Downloader alloc] init];
  
  __block BOOL received = NO;
  [dl startDownloadWithCompletion:^{
    received = YES;
  }];
  
  [self waitWithTimeout:1.1 forSuccessInBlock:^BOOL{
    return received;
  }];
  STAssertTrue(received, nil);
}

This code tests the completion handler of an asynchronous call of a Downloader class (see the example project for details) by waiting for a block to return YES within a given time limit.

What I prefer about this category over the one in GHUnit is that the test is fully contained within the body of the test method. There is no need to implement any other callback method and reference it from this test. This makes copy and paste of tests for re-use much simpler, for example.

Tuesday
Jun052012

Safari: Keyboard shortcut for opening current page in Google Chrome

Currently shipping Macs come without Adobe Flash preinstalled and I’ve been running that same setup without Flash for quite a while now myself. More and more webpages work fine without Flash and only the occasional video requires it. When that is the case, I simply go to the ‘Develop’ menu (enable it in the ‘Advanced’ section of Safari’s preferences if you don’t have it) and select ‘Open Page With’ ➡ ‘Google Chrome.app (20.0.1132.21)’. Since Google Chrome ships with integrated Flash, this is a simple way to switch to a Flash-enabled browser.

Now, rather than having to choose Chrome from the menu it would be nice to be able to assign a keyboard shortcut for this menu item. This is actually quite simple: Open the keyboard preference pane in System Preferences, select ‘Application Shortcuts’ and add a shortcut for the ‘Google Chrome.app (20.0.1132.21)’ menu item to Safari. However, the problem here is that the menu item contains the version number of Chrome and since Chrome updates frequently (and in the background), you’ll find yourself with a broken shortcut very soon.

The fix for this is a little Apple Script OpenURLInNewChromeWindow.app by Mike Hardy which basically tells Google Chrome to open the URL via an Apple Script command. If you run this script once, it will register itself as a application that can handle URLs and will therefore also appear in the list of browsers under ‘Open Page With’. Opening a page with this script will open the current page in Chrome just like before but the point is that the menu command will stay the same no matter what version of Chrome you have installed. Therefore you simply assign the shortcut to this ‘browser’ instead of the ever changing Chrome one.

An added benefit (and actually the reason Mike Hardy wrote the script in the first place) is that the page opens in a new window and not in a new tab (which can be quite annoying when using virtual screens). See Mike’s blog post on more details how to use his script in that context.