An Objective-C API Diff Tool

June 17, 2014

For the last year most of my work has been in Objective-C framework development. With each release I would look through a diff of the headers since the previous release and make note of the API modifications so that users of the framework could easily see what had changed. While not terribly time consuming it was tedious and required some care, especially when declarations were relocated. Having previously contributed to the ObjectDoc project’s Objective-C wrapper for libclang, this seemed like a good opportunity to make use of that work and put together a tool to automate the diff generation. The result is objc-diff, a libclang-based tool to generate an Objective-C API diff report.

The reports generated by the tool (example) are similar to those provided by Apple for the system frameworks, with a couple of improvements:

  • When a class or protocol is moved to a different header a relocation is reported only for that entity rather than it and all of its methods and properties. The relocation of the children is implied and this eliminates a lot of noise from the report.

  • Conversions between explicit accessor methods and @property declarations are reported as modifications to the declaration rather than a series of additions and removals. This more accurately describes the change and makes the actual additions and removals easier to identify.

Binary releases are available on the project page, and the source is available on GitHub.

Clean File Templates for Xcode 4

February 1, 2013

When creating new classes through Xcode I tend to delete just about everything provided in the default file templates. The information in the comment block headers is better tracked by a source control system and I often don’t want the default method implementations. To support this I’ve created a set of file templates that include nothing but an #import appropriate for the base class and an empty @interface and @implementation.

To install these templates create ~/Library/Developer/Xcode/Templates/File Templates if it doesn’t already exist and clone the GitHub repo into a sub-directory name of your choice (I use “Clean”). This directory name will appear as a category in Xcode’s new file dialog. Once installed you can use these instead of the normal Cocoa / Cocoa Touch templates and enjoy one less step when adding new classes to your project.

Disabling Xcode 4.6's Garbage Collection Warning

January 28, 2013

Xcode 4.6 generates a Target Integrity warning if the build setting GCC_ENABLE_OBJC_GCC is set to a value other than “unsupported”, stating that garbage collection is deprecated and encouraging you to migrate to ARC. However, for targets like System Preference panes garbage collection support is still required so GC is enabled for a good reason. In such cases this warning is annoying and there is no obvious way to turn it off. But it turns out that with a little build setting manipulation it is possible.

Set the default value of GCC_ENABLE_OBJC_GCC to “unsupported”, then expand the build setting and for each configuration add a per-architecture setting with a value of “supported”. If you’re using GC for multiple architectures do this for each supported architecture, as using “Any Architecture” will still cause Xcode to complain. You should end up with something like this:

Updated Garbage Collection Build Setting

This silences the warning and allows you to continue to build with GC support, at least for now.

Update: This works in Xcode 4.6 through 5.0.2. Support for garbage collection was removed in Xcode 5.1.

Power Nap and the Network

October 18, 2012

With the introduction of Power Nap developers have something new to think about: applications running while the system appears to be asleep. Every hour Power Nap enabled systems partially wake up and any running applications will briefly execute with disk and network access. In most cases this works just fine, but for some apps it can result in behavior that the user does not expect. For example, consider apps like instant messaging and IRC clients that advertise the presence of a person or service. Every hour they will reconnect to their networks and make it appear as if the user is available when they really aren’t. Such reconnections can also cause downright annoying behavior like the AIM multiple sign-in warning, improper redirection of incoming messages, or an offline IRC buffer being sent to the wrong device.

For apps like these the behavior is likely caused by the application attempting to reconnect in response to a closed connection or low-level network state notifications. Previously this worked as expected because the reconnection code did not run until the user woke up the system, but under Power Nap it is running while the system is still asleep from the user’s point of view. Apps that run into trouble here will need to suspend their reconnect behavior until the system is fully awake, and fortunately this is pretty easy to do. The partial wake state used by Power Nap is known as Dark Wake, and while in this state the NSWorkspaceDidWakeNotification and SCNetworkReachability callbacks are not sent. As a result a simple solution is to watch for the NSWorkspaceWillSleepNotification and disable reconnects or network state observers until an NSWorkspaceDidWakeNotification is received. Alternatively an application can adopt the SCNetworkReachability APIs if possible and rely on those callbacks to inform the app when it is appropriate to reconnect.

If you want to test your changes without waiting an hour for Power Nap to kick in an easy way to trigger Dark Wake for a few seconds is to put the system to sleep then connect or disconnect AC power or a peripheral. This is also useful for testing a direct transition from Dark Wake to full wake by connecting power then pressing a key to wake up the system.

Notification Center Updates for Homebrew

July 25, 2012
Notification Center Homebrew Update

I’ve modified my Homebrew update notification script to use Notification Center thanks to terminal-notifier, a growlnotify replacement that allows posting to Notification Center from the command line. The script now looks like this:

export PATH=/usr/local/bin:$PATH
notifier=/Applications/terminal-notifier.app/Contents/MacOS/terminal-notifier

# Give the network a chance to connect
sleep 10

brew update > /dev/null 2>&1
outdated=`brew outdated | sort | tr '\n' ' '`

if [ ! -z "$outdated" ]; then
    $notifier \
        -group net.codeworkshop.homebrewupdate \
        -title "Homebrew Updates Available" \
        -message "$outdated" \
        -activate com.apple.Terminal > /dev/null 2>&1
fi

The launch agent remains the same, checking for updates every day at 6:00 p.m. or the next time the Mac wakes from sleep. To install, first download terminal-notifier and place it in your Applications folder. Then download the script files and move homebrewupdate into /usr/local/bin and net.codeworkshop.homebrewupdate.plist into ~/Library/LaunchAgents. Then load the launch agent and you should be set.

launchctl load ~/Library/LaunchAgents/net.codeworkshop.homebrewupdate.plist

If you’re upgrading from the Growl version you only need to replace the homebrewupdate script. The launch agent works just as before.