Evergreen Images

Brent Simmons, the original developer of MarsEdit and NetNewsWire, is building a new feed reader app called Evergreen:

Evergreen is an open source, productivity-style feed reader for Macs.

It’s at a very early stage – we use it, but we don’t expect other people to use it yet.

I’ve never been one to shy away from early-stage software, so of course I ran to the GitHub project page, cloned the repository, and built it immediately on my own Mac.

Screenshot of Evergreen about box without a custom icon.

Ahh, the tell-tale sign of a young app: the generic about box. Personally, I like to give apps-in-progress an icon, even if only a placeholder image, as soon as possible. It occurred to me that Apple has done the favor of providing a pretty-darned-suitable image for “Evergreen” in the form of its Emoji glyph of the same name:

🌲

Since I have the source code right here, why don’t I render that tree at a large size in a graphics app, resize it to a million different resolutions, bundle it up and check it in to the Evergreen source base?

Because that’s not nearly as fun as doing it in code. I dove into the Evergreen application delegate class, adding the following function:

private func evergreenImage() -> NSImage? {
	var image: NSImage? = nil
	let imageWidth = 1024
	let imageHeight = 1024
	let imageSize = NSMakeSize(CGFloat(imageWidth), CGFloat(imageHeight))

	if let drawingContext = CGContext(data: nil, width: imageWidth, height: imageHeight, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) {

		let graphicsContext = NSGraphicsContext(cgContext: drawingContext, flipped: false)
		NSGraphicsContext.saveGraphicsState()
		NSGraphicsContext.setCurrent(graphicsContext)

		let targetRect = NSRect(origin: NSZeroPoint, size: imageSize)
		NSString(string: "🌲").draw(in: targetRect, withAttributes: [NSFontAttributeName: NSFont.systemFont(ofSize: 1000)])

		NSGraphicsContext.restoreGraphicsState()

		if let coreImage = drawingContext.makeImage() {
			image = NSImage(cgImage: coreImage, size: imageSize)
		}
	}

	return image
}

In summary this code: creates a CoreGraphics drawing context, renders a huge evergreen Emoji glyph into it, and creates an NSImage out of it.

Then from the “applicationDidFinishLaunching()” function:

if let appIconImage = evergreenImage() {
	appIconImage.setName("NSApplicationIcon")
	NSApplication.shared().applicationIconImage = appIconImage
}

Give the newly created image the canonical name, used by AppKit, for looking up the application icon, and immediately change the application’s icon image to reflect the new value. It worked a treat:

EvergreenEmoji

In programming there is usually a hard way, an easy way, and a fun way. Be sure to take the third option as often as possible.

Resolving Modern Mac Alias Files

When a user selects a file in the Mac Finder and chooses File -> Make Alias, the resulting “copy” is a kind of smart reference to the original. It is similar to a POSIX symbolic link, but whereas a symbolic link references the original by full path, an alias has historically stored additional information about the original so that it stands a chance of being resolved even if the original full path no longer exists.

An alias, for example, can usually withstand being copied from one volume to another. To test this: create a Folder in your home folder called “Test”, and a file within it called “File”. Now, make an alias to “File”. You should have a folder hierarchy that looks like this:

Test
	File
	File alias

Click on the “File Alias” item, then choose “File” -> “Show Original” from the Mac menu bar to see how it resolves to the original.

Now, copy the whole folder to another volume, for example to a thumb drive or other external drive on your Mac. Click on the alias file and “Show Original” again. Instead of resolving to the file on your home volume, it resolves relative to the location on the new volume.

That’s pretty neat.

In the old days, if a developer needed to resolve an alias file on disk, they would use a Carbon function such as FSResolveAliasFile. In recent years, particularly as Application Sandboxing was introduced on the Mac, Apple has shifted away from aliases as a developer-facing concept, towards the use of “Bookmark Data”. As a result, an “alias file” created in the Finder is no longer a traditional alias, but a blob of bookmark data. You can confirm this by examining the hex content of the “File Alias” you created above. From the Terminal:

% xxd File\ alias
00000000: 626f 6f6b 0000 0000 6d61 726b 0000 0000  book....mark....
00000010: 3800 0000 3800 0000 f003 0000 0000 0410  8...8...........
00000020: 0000 0000 0061 0000 768c 979b 7ed8 be41  .....a..v...~..A
00000030: 0000 0000 ff7f 0000 0403 0000 0400 0000  ................
00000040: 0303 0000 0004 0000 0700 0000 0101 0000  ................

It was nice of them to design the format with the tell-tale “book….mark” data right there in the header!

Although you can still use FSResolveAliasFile on these beasts, the function is deprecated and Xcode will warn you about such behavior. The way forward is to use the newer

-[NSURL URLByResolvingBookmarkData:...]

method in Objective-C, or

URL.init(resolvingBookmarkData: ...)

in Swift. Just load the NSData from the alias file’s URL, and pass it to NSURL/URL as appropriate.

There’s a big catch, however, which is that you must take care to pass the alias file’s URL as the “relativeTo:” parameter when resolving the bookmark. Otherwise the bookmark will resolve as expected in typical scenarios, but will fail to resolve in all the scenarios where bookmarks really shine, as for example in the case of moving a bookmark and its target to another volume. So, for example, to resolve an alias file you know exists at “/private/tmp/Test/SomeAlias”:

var targetURL: URL? = nil
do {
	let aliasFileURL = URL(fileURLWithPath: "/private/tmp/Test/SomeAlias")
	let thisBookmarkData = try URL.bookmarkData(withContentsOf: aliasFileURL)
	var ignoredStaleness: Bool = false
	targetURL = try URL(resolvingBookmarkData: thisBookmarkData, options: .withoutUI, relativeTo: aliasFileURL, bookmarkDataIsStale: &ignoredStaleness)
}
catch {
	print("Got error: \(error)")
}

Notice how I ignore the staleness? It’s because I think this notion of staleness is tied more to resolving data with security scope, or in any case a bookmark that you are holding as pure Data, and not one that persists as a file on disk. The safety of ignoring staleness is supported by the fact that, starting in macOS 10.10, there is a new convenience method on NSURL specifically for resolving “alias files”:

var targetURL2: URL? = nil
do {
	let aliasFileURL2 = URL(fileURLWithPath: "/private/tmp/Test/SomeAlias")
	targetURL2 = try URL(resolvingAliasFileAt: aliasFileURL2)
}
catch {
	print("Got error: \(error)")
}

Which takes care of ensuring the “relativeTo:” information is considered, on your behalf. If you don’t need to support Mac OS X 10.9 or earlier, you should use the newest method! Otherwise, I hope the information preceding is of some use.

Better GitHub Searching

Sometimes when I’m searching a GitHub repository, I end up with a ton of uninteresting results because there are, for example, tests or documentation in the repository that are not pertinent to what I’m searching for.

For example, in the Apple Swift repository, searching for “struct String” currently yields 22 results, many of which are in the “test/” subdirectory. I’m not interested in these at the moment.

To search any subpath, just modify the search with the “path:” flag: “struct String” path:/stdlib. Six results, all pertinent to the actual implementation of “struct String”. Just what I was looking for.

There are lots of fancy constraints you can apply to GitHub searches, I simply hadn’t thought to look them up until now. Maybe some of them will make your exploration easier, too.

Debugging Swift: Error in Auto-Import

Have you ever tried debugging Swift code in an embedded framework, and met resistance from lldb in the form of a cryptic AST context error?

error: in auto-import:
failed to get module 'RSAppKit' from AST context:

<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "Headers/RSAppKit.h"
        ^
error: [...]/RSAppKit.h:1:9: error: 'RSAppKit/SomeHeader.h' file not found
#import <RSAppKit/SomeHeader.h>
        ^

error: could not build Objective-C module 'RSAppKit'

After hours of trying to unravel this mystery, I discovered the root cause: the framework that is embedded in my app does not, in fact, contain any headers. They were stripped by Xcode when it copied the framework into the app.

In my opinion, Xcode and/or lldb should be smart enough to handle this situation, by preferring the version of the framework in the “Built Products” directory, which still has its header files in-tact. Radar #31502879 requests this, hopefully Apple will fix it.

In the mean time, you can work around the problem by setting the REMOVE_HEADERS_FROM_EMBEDDED_BUNDLES build setting to NO in the app that embeds the framework:

Xcode build settings showing REMOVE_HEADERS_FROM_EMBEDDED_BUNDLES set to NO for DEBUG builds.

You probably want to make sure it remains set to YES for Release builds, so that you don’t ship your framework’s header files to your customers.

System Level Breakpoints in Swift

Any great software developer must inevitably become a great software debugger. Debugging consists largely of setting breakpoints, then landing on them to examine the state of an app at arbitrary points during its execution. There are roughly two kinds of breakpoints: those you set on your own code, and those you set on other people’s code.

Setting a breakpoint on your own code is simple. Just find the line of source code in your Xcode project, and tap the area in the gutter next to the pertinent line:

MotoAppSwift

But what if you need to set a breakpoint on a system API, or a method implemented in a drop-in library for which you don’t have source code? For example, imagine you are hunting down a layout bug and decide it might be helpful to observe any calls to Apple’s own internal layoutSubviews method on UIView. Historically, to an Objective-C programmer, this is not a huge challenge. We know the form for expressing such a method symbolically and to break on it, we just drop into Xcode’s lldb console (View -> Debug Area -> Activate Console), and set a breakpoint manually by specifying its name. The “b” shorthand command in lldb does a bit of magic regex matching to expand what we type to its full, matching name:

(lldb) b -[UIView layoutSubviews]
Breakpoint 3: where = UIKit`-[UIView(Hierarchy) layoutSubviews], address = 0x000000010c02f642
(lldb) 

If you’re intimidated by the lldb console, or you want the breakpoint to stick around longer than the current debug session, you can use Xcode’s own built-in symbolic breakpoint interface (Debug -> Breakpoints -> Create Symbolic Breakpoint) to achieve the same thing:

Image of Xcode's symbolic breakpoint editor

In fact, if you add this breakpoint to your iOS project and run your app, I am pretty sure you will run into a breakpoint on Apple’s layoutSubviews method. Pop back into the lldb console and examine the object that is being sent the message:

(lldb) po $arg1
<UIClassicWindow: 0x7f8e7dd06660; frame = (0 0; 414 736); userInteractionEnabled = NO; gestureRecognizers = <NSArray: 0x60000004b7c0>; layer = <UIWindowLayer: 0x600000024260>>

Now, continue and break on the symbol again. And again. Examine the target each time by typing “po $arg1” into the lldb console. You can imagine how handy it might be to perform this kind of analysis while tracking down a tricky bug.

But what about the poor Swift programmers who have come to our platforms, bright-eyed and full of enthusiasm for Swift syntax? They who have read Apple’s documentation, and for whom “-[UIView layoutSubviews]” is impossible to parse, whereas “UIView.layoutSubviews” not only looks downright obvious, but is correct for Swift?

Unfortunately, setting a breakpoint on “UIView.layoutSubviews” simply doesn’t work:

(lldb) b UIView.layoutSubviews
Breakpoint 3: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.
(lldb) 

This fails because there is no Swift type named UIView implementing a method called layoutSubviews. It’s implemented entirely in Objective-C. In fact, a huge number of Objective-C methods that are exposed to Swift get compiled down to direct Objective-C message sends. If you type something like “UIView().layoutIfNeeded()” into a Swift file, and compile it, no Swift method call to layoutIfNeeded ever occurs.

This isn’t the case for all Cocoa types that are mapped into Swift. For example, imagine you wanted to break on all calls to “Data.write(to:options:)”. You might try to set a breakpoint on “Data.write” in the hopes that it works:

(lldb) b Data.write
Breakpoint 11: where = libswiftFoundation.dylib`Foundation.Data.write (to : Foundation.URL, options : __ObjC.NSData.WritingOptions) throws -> (), address = 0x00000001044edf10

And it does! How about that? Only it doesn’t, really. This will break on all calls that pass through libswiftFoundation on their way to -[NSData writeToURL:options:error:], but it won’t catch anything that calls the Objective-C implementation directly. To catch all calls to the underlying method, you need to set the breakpoint on the lower level, Objective-C method.

So, as a rule, Swift programmers who want to be advanced debuggers on iOS or Mac platforms, also need to develop an ability for mapping Swift method names back to their Objective-C equivalents. For a method like UIView.layoutSubviews, it’s a pretty direct mapping back to “-[UIView layoutSubviews]”, but for many methods it’s nowhere near as simple.

To map a Swift-mapped method name back to Objective-C, you have to appreciate that many Foundation classes are stripped of their “NS” prefix, and the effects of rewriting method signatures to accommodate Swift’s API guidelines. For example, a naive Swift programmer may not easily guess that in order to set a breakpoint on the low-level implementation for “Data.write(to:options)”, you need to add back the “NS” prefix, explicitly describe the URL parameter, and add a mysterious error parameter, which is apparently how cranky greybeards used to propagate failures in the bad old days:

(lldb) b -[NSData writeToURL:options:error:]
Breakpoint 13: where = Foundation`-[NSData(NSData) writeToURL:options:error:], address = 0x00000001018328c3

Success!

For those of you mourn the thought of having to develop this extensive knowledge of Objective-C message signatures and API conventions, I offer a little hack that will likely get you through your next challenge. If the API has been rewritten using one of these rules, it’s almost certain that the Swift name of the function is a subset of the ObjC method name. You can probably leverage the regex matching ability of lldb to zero in on the method you want to set a breakpoint on:

(lldb) break set -r Data.*write
Breakpoint 14: 107 locations.

Now type “break list” and see the massive number of likely matches lldb has presented at your feet. Among them are a number of Swift cover methods that are part of libswiftFoundation, but you’ll also find the target method in question. In fact, you’ll also see a few other low-level Objective-C methods that you may want to break on as well.

To make the list more manageable, given your knowledge that the target methods are in a given Objective-C framework, add the “-s” flag to limit matches to a specific shared library by name:

(lldb) break set -s Foundation -r Data.*write
Breakpoint 17: 8 locations.

Among these breakpoints there are a few false hits on the NSPageData class, but the list is altogether more manageable. The single breakpoint “17” has all of its matches identified by sub-numbers. Prune the list of any breakpoints that get in your way, and you’re good to go:

(lldb) break disable 17.6 17.7 17.8
3 breakpoints disabled.
(lldb) c

Apple’s mapping of Objective-C API to Swift creates an altogether more enjoyable programming experience for Swift developers, but it can lead to great confusion if you don’t understand some of the implementation details, or how to work around lack of understanding. I hope this article gives you the tools you need to debug your Swift apps, and the Objective-C code that you are unavoidably leveraging, more effectively.

Update: I filed two related bugs: Radar #31115822 requesting automatic mapping from Swift method format back to underlying Objective-C methods, and Radar #31115942 requesting that lldb be more intuitive about evaluating terse Swift method signatures.

Implicit Swift Dependencies

If you’re developing in Swift for Mac or iOS, you need to ensure that any standard Swift libraries are also copied into your app bundle. Typically this is handled automatically by Xcode when it detects the presence of any Swift files in your app. If your app is entirely Objective-C, but you link against your own frameworks that themselves depend on Swift, you have to ensure the required libraries are embedded. This can be done by setting the “Always Embed Swift Standard Libraries” checkbox in your target’s build settings to “Yes”:

AlwaysEmbed

When this option is set, Xcode scans the bundled frameworks in your app and, if any of them contains Swift code, it copies the pertinent libraries into your app’s bundle.

This approach falls down a bit when it comes to Unit Testing targets. Because a Unit Test bundle doesn’t typically copy the framework it is testing into its own bundle, Xcode seems to deduce dependencies by examining the list of frameworks the test bundle links to. If you enable the “Always Embed” option above for a Unit Testing bundle, then any framework the bundle links against will be examined for Swift code, and the required libraries copied in.

But what if none of the linked frameworks themselves require Swift, but they depend upon other frameworks that do? In projects of a substantial size, you may have higher-level frameworks implemented entirely in Objective-C, that depend upon lower level frameworks that use Swift. In this scenario, Xcode’s CopySwiftLibs build phase does not identify the deeper dependency, and neglects to embed the required Swift libraries. When your unit tests run, you’ll see a runtime error like this:

The bundle "RSTextFilteringTests" couldn’t be loaded because it is damaged or missing necessary resources. Try reinstalling the bundle.
(dlopen_preflight([...]/RSTextFilteringTests): Library not loaded: @rpath/libswiftAppKit.dylib
  Referenced from: [...]/RSAppKit.framework/Versions/A/RSAppKit
  Reason: image not found)
Program ended with exit code: 82

So “Always Embed Swift Standard Libraries” doesn’t always embed them. I’ve filed Radar #30832923, requesting that the CopySwiftLibs build phase look harder for Swift dependencies. In my opinion it should look not only at the directly linked frameworks, but at any developer-supplied frameworks that those in turn depend upon. This would cause “Always Embed” to behave as expected when a developer adds Swift dependencies to frameworks at any level of their code base.

There are many possible workarounds to the problem, and each has its own drawbacks. Here are a few:

  1. Add a Swift-based unit test file to your test bundle. This simple workaround will work in most situations, because the test itself will impose many Swift library dependencies on your bundle. There is a shortcoming, though: if the test code doesn’t generate all the Swift dependencies that your frameworks do, you’ll still be left with missing Swift libraries. For example if a dependent library requires the Swift library for Apple’s Contacts.framework, your Swift test file is not sufficient to cue Xcode to copy the required libSwiftContacts library.
  2. Manually link to Swift-dependent frameworks. Suppose your unit tests target HighLevel.framework, and LowLevel.framework depends upon Swift. By adding LowLevel.framework to the list of linked libraries for your testing bundle, you will cue Xcode to also embed the required Swift libraries for that framework. This has the advantage of ensuring that whatever Swift libraries are required get copied, but it has the drawback of requiring explicit dependency on a lower level framework from your unit test bundle.
  3. Stop! Abort mission! Revert to Objective-C only. Many Swift dabblers probably feel this emotion from time to time. The unexpected costs of adding a modest amount of Swift to a project are frustrating, and one can’t help but wonder whether they would be better off waiting until Swift support is more baked in to the system. The obvious downside of this approach is that Apple’s progress with Swift is moving quickly, and the longer you put off testing the waters, the harder it may be for you to catch up when ignoring it is no longer a viable option.

The workaround I’ve settled on for now is #2. Adding unnecessary direct dependencies to my test bundle feels a little inappropriate, but it is both easily undone in the future, and unlikely to cause any real problems in practice.

In the course of investigating this problem, it also occurred to me that unit test bundles in particular are such a special case, that Apple should probably give them special treatment to eliminate a number of pitfalls. I filed Radar #30832983 suggesting that unit test bundles should default to “Always Embed Swift Standard Libraries,” on the assumption that Swift code may be present in some library.

Thinking further on that point, it seems that Unit Tests could be safely run in an environment in which all Swift support libraries are available at runtime to be resolved by DYLD. Because test bundles are not built to be shipped to customers, it’s of primary that they link and run successfully. Such an approach would do away with the need for Unit Test bundles to either specify that Swift libraries be bundled, or to fret about which of those libraries in particular need to be copied.

Interface Builder: View Is Clipping Its Content

If you have Xcode’s “Show live issues” enabled, you’re used to seeing (usually) helpful warnings and notices about your source code and interface files. These notices appear even if you haven’t yet built your project:

Image of Xcode Interface Builder warning about a view clipping its content.

If you click the “View is clipping its content” notice, it takes you right to the view in question:

Image of a popup button on the Interface Builder canvas.

At this point you can usually just “size to fit” and Interface Builder will use its knowledge of the control’s class, and that class’s ability to size itself to suit its content. Or, if you’re using Auto Layout, it might mean that you need to ask Interface Builder to update the items’s frame, allowing Auto Layout to essentially size to fit for you.

In this case however I have a conundrum: both “size to fit” and AutoLayout insist this is the proper size and placement for the control, yet Interface Builder is still convinced the control will clip its content (the text of the menu item title).

What happens if I naively attempt to increase the width of the popup button?

Image of a popup button with error messages indicating it is the wrong width.

The clipping area is gone, as Interface Builder is convinced the button is now wide enough, but that width is in conflict with what Auto Layout is convinced is the right width.

I can’t win: if I let Auto Layout have it’s way, I get an annoying clipping notice. If I let the clipping notice have its way, Auto Layout throws a fit.

One workaround, when working with Auto Layout, is to provide a bogus constraint that forces the width of the popup button to the width that I’ve manually imposed. By setting it to “Remove at Build Time” it should not have any effect on the behavior of your interface, except in Xcode itself.

WidthConstraint

See that empty “Identifier” field? I have actually taken advantage of that field as an opportunity to add a memo to myself for future reference: “Work around bug 25938”. This references my internal bug tracking the issue, so I can re-acquaint myself with the problem if I find myself wondering about this bogus constraint in the future.

It seems to me the bug here is either that NSPopUpButton sizes to fit at too narrow a size, technically causing “clipping” of its subviews. Alternatively, Interface Builder’s deduction of a view’s size causing clipping has some bug in it. Either way, I’ve filed the issue as Radar #30222922.

Update, January 28, 2017: Thanks to a tweet from Mark Lilback, I discovered the notice about clipping is a bit less pervasive than I thought. The notice only seems to appear when Xcode has the xib file actively open for editing with Interface Builder. What this means practically is that you have to click on the xib file at some point and have the editor appear for it, before the notice appears. It also means that if you cause Xcode to close the file for editing, the notice disappears. You can close any file in Xcode by focusing on its editor and then selecting File -> “Close <filename>”, or by pressing Cmd-Ctrl-W.

I have always found these kinds of notices in Xcode to be somewhat unpredictable. The fact that the file has to be actively opened for editing, combined with the fact that files remain open in Xcode after their editor is visually swapped out, explains most of the apparent inconsistencies I’ve seen.

Unbuffering Jenkins Output

For years I have used Jenkins to manage all my automated Mac and iOS builds. I have jobs set up to build and release apps “on demand,” as well as integration builds that kick off whenever a change is made to a pertinent source code repository.

For years I have also put up with a small but vexing nuisance that when something goes wrong with a build, I have to search in the most unlikely place for pertinent informational messages printed by my build scripts: at the very bottom of the log.

I had chalked it up for so long to being a nuanced Jenkins bug, that I never took the time to get down to basics and really unwrap what is going on. Today, I did that, and also came up with an easy solution.

I use a custom script to drive the whole process for each of my automated builds. This script is responsible for printing diagnostic information and for invoking other tools (such as xcodebuild) to get the actual work of building, testing, and uploading done.

The problem with the misplaced log lines in my console output has to do with a feature of the scripting language I use to drive the process: standard output buffering. I use Python, but the problem could also affect you if you use a language such as Ruby to drive your automation.

Here’s a contrived example of a build script that will exhibit the problem. If you create a new, empty Jenkins build job, and configure it with a single “Execute Shell” build task:

#!/usr/bin/python 

import os

print "start"
os.system("ls -ld /Applications/TextEdit.app")
print "end"

You will find the generated console output upon “building” this job is demonstrably out of order:

[workspace] $ /usr/bin/python /var/folders/wh/f_vmqvxx34d69c1pm191t0tr0000gq/T/hudson321577740740596707.sh
drwxr-xr-x@ 3 root  wheel  102 Dec 13 14:00 /Applications/TextEdit.app
start
end

The message from the “ls” subprocess prints right away, but Python buffers the output until it’s done running, leading a nonsensical printing of the “start” and “end” messages after the job is completely done.

Now I will make a tiny change, passing the “-u” parameter to the Python invocation in the script. This option is documented to “Force stdin, stdout and stderr to be totally unbuffered”:

#!/usr/bin/python -u

Running the job again in Jenkins produces the expected output in Jenkins:

[workspace] $ /usr/bin/python -u /var/folders/wh/f_vmqvxx34d69c1pm191t0tr0000gq/T/hudson3255283214356026397.sh
start
drwxr-xr-x@ 3 root  wheel  102 Dec 13 14:00 /Applications/TextEdit.app
end

This is a small annoyance in this example, but in a real-world scenario it means that the pertinent xcodebuild invocation, which I print to the console before calling, will now show up where it belongs in the console log, making it much easier for me to reason about the behavior of my automated builds when they aren’t working as they should.

Touch Bar Crash Protection

I wrote previously about crashes related to Apple’s Touch Bar. These crashes seem to affect all apps that were built with a certain toolchain. Most likely it affects all apps that were built against an SDK of a certain vintage. For example, some of my apps that are still built against a 10.6 SDK crash on Touch Bar Macs, either frequently or infrequently, depending upon the user.

I had hoped that we might see a fix from Apple in macOS 10.12.2, but alas the issue is still there. This left me feeling obligated to my customers to find a solution that I can deploy soon. I don’t know if Apple considers the crashes a problem worth pursuing, and if so, how soon they plan to deliver a fix.

Poking around the AppKit infrastructure supporting the Touch Bar, I discovered a secret NSUserDefaults setting, NSFunctionBarAPIEnabled, which seems to determine whether the system exposes an app to the Touch Bar at all. It defaults to YES, but if it’s set to NO for an app, I think the app remains more or less invisible to the Touch Bar.

I have very reproducible test cases for many apps, including Apple’s own SystemUIServer process, so I decided to play around with the NSFunctionBarAPIEnabled user default and see how things go. To my satisfaction, setting the value explicitly to NO for any of the affected apps completely eliminates the crashes:

defaults write com.apple.systemuiserver NSFunctionBarAPIEnabled -bool NO

SystemUIServer is an interesting example, because I can’t honestly imagine what I’m giving up by disabling Touch Bar support in the app. It’s probably a case where having the default on by default is exposing it to bugs in the Touch Bar infrastructure, even though it will never benefit by having Touch Bar support enabled.

Other apps are not so clear cut: you might have an affected app on your Mac that “works with the Touch Bar,” even though it doesn’t do anything special to support it yet. My own app, MarsEdit, is one such app. The Touch Bar works when you’re focused in on some system-standard UI element such as a text view, but it doesn’t do anything special throughout most of the app. In a situation like this, if you are suffering many crashes as a user, you might decide to do something like the above, writing a custom NO setting to the NSFunctionBarAPIEnabled value. Be aware, however, if you do this that you’ll lose Touch Bar functionality for that app forever, or at least until you remember you set this funny default value.

Getting back to my motivation to eliminate these crashes as soon as possible for my customers, I think that I will ship an update to MarsEdit that disables the Touch Bar, but does so in a transient manner. By registering a default value in the app itself I will not force users to save any permanent value in preferences, and will also give them the ability to override my judgement as they see fit. If you wanted to do something like this in an app, you could add a few lines like this to main.m:

NSDictionary* myDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"NSFunctionBarAPIEnabled"];
[[NSUserDefaults standardUserDefaults] registerDefaults:myDict];

You want to put this early in your app’s launch, so that it’s registered before AppKit’s Touch Bar infrastructure loads up. When it sees that NSFunctionBarAPIEnabled is set to NO, it will kindly avoid initializing the classes which are evidently making many apps prone to crashes on Touch Bar Macs.

I haven’t decided for sure yet whether to ship with this in place, but unless I find a more suitable workaround, I think I will. Disabling Touch Bar support entirely in the short term will be preferable to subjecting my customers to unpredictable crashes that are out of my control.

Installing Symbols For WatchOS

For months I have been plagued by Xcode’s persistent failure to successfully install WatchOS device support on my Mac. If I open Xcode, and my iPhone (paired with an Apple Watch) is attached to the Mac, I am greeted by a progress indicator such as this:

InterfaceController swift

Because I don’t actually do any watchOS development, this has mostly been a mild annoyance. The bug doesn’t seem to affect the performance of my Mac, and other actions I perform in Xcode continue without delay. However, for those of you who are actually doing Watch development, if you run into this problem, you’ll be perpetually greeted by this error when you try to debug on a real device:

Xcode panel refusing to install on a device because of missing Apple Watch symbols.

The worst side-effect of this bug for me, and the problem that finally encouraged me to hunker down and solve the issue, is the fact that each attempt to “Install Symbols” is associated with a fresh download of a larger-than-200MB file from Apple to my Mac. This is no big deal on my home network, but when I’m roaming and tethered to my bandwidth-metered iPhone, it can lead to costly overage charges.

I’ve been to hell and back tracking down exactly how Xcode installs these symbols, where it fails, and how to work around the problem. I’ll give an overview of how Xcode’s symbol installation process works, and walk you through one concrete method for working around the problem, getting those precious symbols installed, and breaking the cycle of perpetual failed installations.

Symbol Installation Overview

First I want to give you a high level idea of how Xcode downloads and installs symbols. Here are the steps that take place:

  1. A device suitable for development is connected.
  2. Xcode looks for existing symbols in the suitable home directory location
  3. If symbols are not already installed, the symbol-installation process begins.
  4. A disk image file containing the required materials is downloaded to a temporary folder.
  5. The disk image file is copied to a Caches subfolder in your home directory.
  6. The disk image is mounted at a temporary location on your Mac
  7. A macOS Installer package on the disk image is used to install symbol files directly into your home folder.
  8. The temporary disk image is unmounted.
  9. The cached disk image file is deleted.

In my tests, the failure to successfully install watchOS symbols broke down in step 7, where the package is supposed to successfully copy symbol files into my home folder. I was able to determine that the Apple infrastructure responsible for the installation is failing on my Mac with a cryptic authentication error:

Could not download and install Symbols for watchOS 3.1 (14S471). Authorization is required to install the packages

The failure is not happening in Xcode per se, but in a helper tool that is part of the private PackageKit.framework. I filed Radar #29568241, in the hopes that somebody at Apple will have insight as the root cause of the problem, and how it can be fixed for good in either Xcode, or in the configurations of affected users’ Macs.

Fix It Yourself

To manually accomplish what Xcode is failing to do, we need to:

  1. Get a copy of the downloaded disk image.
  2. Copy the pertinent files out of the disk image’s installer package.
  3. Copy the pertinent files into the correct installation path in ~/Library/Developer/Xcode/

Because simply creating the directory at the installation path is enough to stop Xcode attempting to install symbols, I’m going to cover that first. Folks who don’t need or want the symbols for Watch development will solve the problem sufficiently after this step.

Determine the Installation Path

Unfortunately, the path is quite specific to the Watch device at hand, and may be difficult to guess. Here’s one way of figuring it out. Making sure you have an iPhone connected that triggers the symbol installation in Xcode, do the following:

  1. Quit Xcode.
  2. From the Terminal, navigate to Xcode’s binary executable folder:
    cd /Applications/Xcode.app/Contents/MacOS/
  3. Run Xcode with a special flag to cause additional logging to display:
    ./Xcode -DVTDownloadableLogLevel 3
  4. Wait for Xcode to launch and start installing symbols.
  5. Scan the output in Terminal for a line like this:
    Starting a download for Watch1,2 3.1 (14S471), to file path /Volumes/Data/daniel/Library/Developer/Xcode/watchOS DeviceSupport/Watch1,2 3.1 (14S471)/Symbols

    Of course, your output will be slightly different, but depending on the version of Watch and watchOS you have, the important part is relative to your home folder. In my case, I need to make sure this folder exists:

    ~/Library/Developer/Xcode/watchOS DeviceSupport/Watch1,2 3.1 (14S471)/Symbols

If you don’t care about Watch development, this is your big chance: just create that folder now. Quit and relaunch Xcode again, and you’ll see that your problems are over. No more symbol installations required. If you skim the logging output from above you’ll see that the “InstalledIfAllPathsArePresent” key in one of the dictionaries indicates that the path merely being present is enough to convince Xcode it’s “installed.”

If you do care about Watch development, you’re going to want those symbols. Let’s tackle that problem next.

Getting the Disk Image

Remember back in “Symbol Installation Overview,” I described the installation failing in step 7: where a package on a mounted volume is attempted to be installed. Unfortunately, this failure does not prevent steps 8 and 9 from proceeding, so when the whole procedure is over, there are no obvious artifacts left around to work with. The disk image, that was copied to ~/Library/Caches/com.apple.dt.Xcode/Downloads in step 5, is available for such a short period of time, you’re unlikely to nab it before Xcode deletes it upon failure.

You may have noticed in the Xcode logging output that many URLs to web resources are passed around. It’s likely that one of these contains the required disk image content, but I thought it would be safer to catch Xcode in the act and use precisely the disk image file that it itself was intending to use.

Yet another “secret” Xcode user default key can help us here. Once again, navigate to the Terminal to execute Xcode manually. This time, we’ll pass a flag that instructs it explicitly not to delete the coveted disk image file after it’s done:

./Xcode -DVTDownloadableLeaveTemporaryFiles 1

This time you’ll have to wait again until the process tries, and fails, but when you’re done you should find a suitable disk image file waiting for you at:

~/Library/Caches/com.apple.dt.Xcode/Downloads/Xcode.Symbols.Watch1,2.14S471-3.1.dmg

(Or with whatever name is suitable for the version of Watch and OS you are accommodating.)

Copying the Symbol Files Out

Double-click the disk image to mount it on your Mac. You’ll find a volume appears with a suitable device-oriented name, and a matching file within called e.g. “Watch1,1_Watch1,2.pkg”.

Warning: Do not open and install this package willy-nilly without reading the following carefully. This is a standard Installer package, and double-clicking it on your Mac will launch the system-standard Installer application. However, agreeing to let it “just install” on your Mac could have unintended consequences. The files in this package are named very similarly to many system files on your Mac, but of course these files are binaries for a ARM based Watch device, and not an x86_64 personal computer.

There are many techniques for getting the files out of an Installer Package without actually, you know, installing. You could use an app like Pacifist to extract them directly to a folder on your disk. There may also be a way to invoke the command-line “installer” tool in such a way that it simply spits the files out where you want them. For that matter, it might be safe to simply “Choose Folder…” from the Installer app, and trust that it will install everything in that folder instead of on the root of the volume.

Me? I decided to strike a semi-paranoid compromise. I used the Installer app, but instead of installing to my Mac’s main volume, I created a writable disk image in Disk Utility, and targeted that volume explicitly:

WatchHack

When the installation was complete, I had a mounted volume, filled with the contents that Xcode has presumably been intending to copy into my home folder.

WatchHack

Finish the Job

At this point you know correct install location in your home folder, and you have a copy of all the files that should be there. It should be as simple as selecting the files from “WatchHack” and dragging them to the “Symbols” folder in the appropriate ~/Library/Developer subfolder.

When the symbol files have been copied in, quit and relaunch Xcode. Not only should it avoid that nasty “Installing Symbols” phase, but building and running on your physical watchOS device should once again work as expected.