Monthly Archives: April 2016

Test With Swift

I have recently passed a sort of tipping point where I’m indulging more and more in Swift for new code that I add to my projects. There are some instances where I will still create a new class in Objective C, primarily where I anticipate the need for dynamic runtime hijinx that might be more complicated in Swift. In general though, I’m opting for Swift. Finally.

There are many reasons to remain gun-shy about Swift, and I don’t fault anybody too much for choosing to continue forestalling the transition. I’ve spoken with many people who are as tentative as I was or moreso. Some of our collective reasons for waiting may sound familiar to you:

Swift …

  • … is not mature.
  • … requires adding bloated libraries to the app.
  • … presents an impedance mismatch with existing Cocoa design patterns.
  • … is still too risky for production code.

I don’t agree with all of these rationale, especially now that I’ve decided to dive in myself. However, they make a good basis for the argument I’d like you to consider: you should write all new unit tests in Swift.

For many of us who spent years developing a vast collection of Objective-C based classes, it does seem daunting to transition to a new language. But unit tests are different from “regular code” in a number of ways that make them a suitable place to start delving into Swift:

Unit tests …

  • Don’t ship to customers.
  • Can be as bloated as you like.
  • Test the exposed interfaces of classes more than the internal design.
  • Are not technically production code.

I’m sure somebody will argue that tests are so vital to the development process, that they are the last place one should invest in risky technology. I guess what I’m urging you to believe is that Swift is no longer risky technology. It’s not longer coming, it’s here. We will serve ourselves well to adopt it as quickly as practical. And those of us who are daunted by the challenge incorporating it into our existing, Objective-C heavy source bases, have a perfect opportunity in unit testing to get our feet wet while establishing a Swift source base that will live on well into the future. After all, your unit tests should, in theory, outlive any specific implementations of your shipping code.

Principally Unclassy

I had a real head-scratcher of a bug with MarsEdit, manifesting as a subtle failure of specific AppleScript commands to work properly in the release builds of the app. It seemed as though AppleScript were unable to reckon any properties of my app stemming directly from the application object itself.

I was so perplexed that I found myself digging around inside AppleScript’s own internal handling of the command. Setting a breakpoint on -[NSScriptCommand executeCommand], I could trace the evaluation of the request from AppleScript, watching as it ultimately failed to handle the command and returned an error.

It made sense to discover that, in the course of determining how to handle the command, it would consult the application’s “top level object.” That is, the application object itself. I witnessed that AppleScript internally determines the object by calling something like this:

(lldb) po [[NSScriptExecutionContext sharedScriptExecutionContext] topLevelObject]
<NSApplication: 0x618000160600>

Well, that all looks pretty ordinary. Nothing to be alarmed by, right? Luckily, it jumped out at me as all wrong, even though it’s the subtlest of things. The instance returned above is of class NSApplication, which would normally be fine, except that I’ve subclassed NSApplication in my app. It should be of class MEApplication.

Apple doesn’t encourage subclassing NSApplication, but it’s well-documented and appropriate in some circumstances. I happen to implement some of MarsEdit’s high level scripting support in the NSApplication subclass.

I double-checked the target’s Info.plist file. Sure enough the value for NSPrincipalClass is “MEApplication”, so why am I getting an NSApplication instance instead? And why did this suddenly start happening in recent beta test releases of the app?

The answer is that I added an innocuous looking call to -[NSApplication sharedApplication] in MarsEdit’s main.m, before the call to NSApplicationMain. And this code path doesn’t get reached on Debug builds, only on Release ones. Sigh.

It’s in NSApplicationMain that the documented behavior occurs of looking up NSPrincipalClass from the Info.plist, and using that value to call -[WhateverClass sharedApplication]. By calling -[NSApplication sharedApplication] before that, I preemptively force the shared application instance to be of class NSApplication.

So remember, kids: don’t subclass NSApplication. But if you do, then don’t reference -sharedApplication before NSApplicationMain. And if you simply must, then make darned sure you explicitly target your custom subclass by name. For you iOS developers, this wisdom applies to UIApplication, as well!

Nasty. Yeah.

Careful What You Wish For

I am a well-known proponent of bug filing. In fact, I filed a bug last year that argued Xcode should apply the custom Code Signing Flags for a project when code signing the bundled Swift libraries that are installed in in an app’s bundle.

I noticed that at some point along the way, Apple did fix the bug! Exciting! Time to rejoice, no? Well, no. Because while the fix for the bug addressed my original complaint, it brought a new headache which I hadn’t anticipated.

For my app MarsEdit, I supply a custom designated requirement for the code signing phase. The long and short of this approach is that through careful specification of a designated requirement, you can arrange it so that if the user stores an item in the keychain from one version of your app (say the Mac App Store version), then the same app can access the data later without prompting the user, even if it has a different bundle ID, or is signed by a different identity (say, because it’s a direct sale version).

The problem I’m running into now, as I dabble with adding Swift-based code to MarsEdit, is the bundled Swift libraries are being signed with my app’s custom designated requirement. Oops. This never would have happened if Apple hadn’t … fixed the bug I reported.

I’m not sure what the right solution is, or even how to best approach a workaround. The copying of Swift libraries and their subsequent signing is not only opaque to developers, but it happens after the entire user-configurable build process is done. It seems as though to work around the problem in such a way that I can still supply a designated requirement for my app, I may need to avoid adding the flag to OTHER_CODE_SIGNING_FLAGS, and amend the designated requirement on my own sometime after the Xcode build process is complete.

I find the code signing configuration options to be pretty troubling for this reason, among others. The highest level code signing identity (and now flags) are used implicitly by Xcode for some code signing operations that are opaque to developers. It puts us in a bind when something subtle turns out to be not quite right with the resulting built product.

I filed a new bug, Radar #25579693, to raise the issue with Apple about the can of worms that fixing my previous report has caused. In the mean time, I’m on the hunt for workarounds! I’ll update this post when I feel I’ve got something good.