Category Archives: Apple

Window Tabbing Pox

macOS Sierra introduces a new system-wide window tabbing feature, which by default enables tabs within the windows of most document-based apps. Apple’s own TextEdit is a canonical example: open the app and select View -> Show Tab Bar to see how it looks.

Unfortunately, the default tabbing behaviors doesn’t make sense in all apps, even if they are document-based. I’ve had to disable the functionality in both MarsEdit and Black Ink, at least for the time being. Doing so is easy. Just add the following line somewhere early in the lifetime of your app:

NSWindow.allowsAutomaticWindowTabbing = NO;

This class property on NSWindow shuts the whole window tabbing system out of your app, so you don’t have to fuss with how to disable it on a window-by-window basis. Handy!

Unfortunately, setting that property to NO doesn’t do anything about windows that may already have been created, and which have their tab bar visible. I added the line to my app delegate’s applicationDidFinishLaunching: method, assuming that would take care of everything. After all, any documents will be instantiated later in the app’s lifetime, right? Right?

Wrong. Not with window restoration, at least, which causes a freeze-drying and restoration of open document windows when a user quits and relaunches the app. The window in this circumstance is actually created before applicationDidFinishLaunching. If it had its tab bar visible when you quit, it will have the tab bar visible when it’s restored, even if you’ve since disabled all window tabbing for the app.

What’s worse? Showing or hiding the tab bar on any window sets that choice as the default for all future windows in the app. So even new documents that are created by users, and which don’t have their tab bar visible because you’ve disabled it app-wide, will have a tab bar appended when they are restored at launch time, because “Show Tab Bar” was the last user action before disabling tabbing altogether.

The long and short of it? An app stuck in this situation will not have a View -> Show/Hide Tab Bar, and none of its windows will support tabbing, except for any document that is restored at launch time. Even new documents that are created without tab bars will have the tab bar imposed the next launch.

I filed Radar 28578742, suggesting that setting NSWindow.allowsAutomaticWindowTabbing=NO should also turn off window tabbing for any open windows that have it enabled.

If your app gets stuck in this predicament, one workaround is to move the NSWindow.allowsAutomaticWindowTabbing=NO line to an even earlier point in your app’s lifetime, such as in your app’s main.m or main.swift file.

Xcode 6 On Sierra

Xcode 6 and Xcode 7 are not supported by Apple on macOS Sierra, and should not be used for production work.

But what if you have a good reason for running one or the other? Maybe you want to compare a behavior in the latest Xcode 8 with an earlier version of the app. Instead of keeping a virtual machine around, or a second partition with an older OS release, it is liberating to be able to run and test against older versions of Xcode.

So far, it appears that Xcode 7 “mostly works” in spite of being unsupported by Apple. I’ve run into some launch-time crashes, but reopening the app tends to succeed.

Xcode 6 will flat out fail to launch, because one of its internal plugins depends on a private framework (Ubiquity.framework) that is no longer present on macOS Sierra. If you were willing to hack a copy of Xcode 6, however, you could get it running. You definitely shouldn’t do this, but if you’re curious how it could be done, here’s how:

  1. Always have a backup copy of any data that is important to you.
  2. Locate a copy of /System/Library/PrivateFrameworks/Ubiquity.framework from the previous OS X release.
  3. Copy the framework to within Xcode 6’s own Contents/Frameworks bundle subfolder:
    ditto /my/old/System/Library/PrivateFrameworks/Ubiquity.framework ./Xcode.app/Contents/Frameworks/Ubiquity.framework
  4. Navigate to the problematic Xcode plugin and modify its library lookup table so that it points to the app-bundled copy of Ubiquity.framework, instead of the non-existent system-installed copy.
    cd Xcode.app/Contents/PlugIns/iCloudSupport.ideplugin/Contents/MacOS
    install_name_tool -change /System/Library/PrivateFrameworks/Ubiquity.framework/Versions/A/Ubiquity @rpath/Ubiquity.framework/Versions/A/Ubiquity ./iCloudSupport
    
  5. Now that you've modified Xcode, its code signature is invalid. You can repair it by signing it with your own credentials or with an ad hoc credential:
    codesign --deep -f -s - ./Xcode.app
    
  6. Did I mention you really shouldn't do this?

Apple has good reason to warn people off running older versions of Xcode, but if you absolutely need to get something running again, it's often possible.

Swift Maturity

Ted Kremenek of Apple announced on the Swift evolution announcements mailing list that the team will no longer accept source-breaking changes for Swift 3. That is, changes that would require developers’ own Swift code to change. He notes that this means many desirable features will not make the cut, and will have to be pushed to Swift 3.1 or beyond:

The challenge of course is reconciling these diametrically opposing goals: maintaining source stability while having the ability to incorporate more core (and important) language changes that are possibly source-breaking.

How will they balance this going forward? He hints that the team wants to support a mechanism whereby developers can specify a version of Swift as a parameter to the compiler. Your code builds against Swift 3.1? The Swift 4 compiler will be able to handle that:

Our goal is to allow app developers to combine a mix of Swift modules (e.g., SwiftPM packages), where each module is known to compile with a specific version of the language (module A works with Swift 3, module B works with Swift 3.1, etc.), then combine those modules into a single binary.

This is great news for developers, but only strengthens my argument that Swift needs a mechanism for SDK-conditional compilation. At this point, a developer who wishes to maintain source code that compiles against, say, iOS 9 and iOS 10, must conditionalize on the version of Swift:

#if swift(>=2.3)
	// iOS 10 only code
#else
	// iOS 9 friendly code
#endif

When and if Ted Kremenek’s promise of a multiversioned Swift compiler comes to pass, it will presumably mean multiple versions of Swift can compile against the same SDK, so this fragile workaround will no longer … work.

Update: It occurs to me, multiple versions of Swift already do build against the same SDK. Currently we have Swift 2.3 and Swift 3 building against Apple’s latest beta SDKs. It’s the “>=” in the workaround that guarantees a suitable SDK match for now.

Brent’s Swift Tension

Brent Simmons has been writing new code exclusively in Swift for a while now, and he recognizes omissions from the language that he still anticipates will be hard to overcome as Apple presumably moves toward incorporating Swift into its developer-facing frameworks. The Tension of Swift:

The Objective-C runtime allows AppKit and UIKit to provide some powerful features that I’d hate to do without: the Responder Chain, xib and storyboard loading, KVC, and the undo manager.

A key point he gets at is that however great Swift is, it’s only possible to use it to develop functional iOS and Mac apps because of the Objective C runtime still operating behind the scenes. Both AppKit and UIKit not only lean on the functionality of the runtime, but are designed with the runtime in mind.

Some major design priorities of the Swift language, namely type safety and compile time dependency binding, are at odds with the design priorities of 20 years of evolution in Apple’s frameworks. How and if that disparity will be reckoned by Apple remains to be seen.

I’m optimistic, because the Swift team has already made many concessions to make the language more compatible with the Objective C runtime. It strikes me as possibly non-optimal that a language that strikes the right compromise between Swift’s priorities and Objective C’s would start at the opposite extreme and work its way backwards, but that is what Apple seems to be doing.

Let’s hope they continue in that direction, and surprise us all with how well it all works out in the end.

Mac App Store Sandbox Testing

For months, many of us Mac developers have noticed that apps built for Mac App Store submission could no longer be tested using iTunes Connect “sandbox” users. Previously, a sandbox user account could be used to authenticate and download a _MASReceipt for a Mac app, to ensure that in-app receipt validation is working as expected. After updating to 10.11.2, many of us noticed that this functionality suddenly stopped working:

At first, we assumed it was a bug. But as time went on, it started to seem as though it could be related to Apple’s announcement that one of its key certificates was expiring.

Still, the communication from Apple about this issue was poor enough that it wasn’t obvious what exactly we needed to do. Even though the page linked above has a section explicitly listing what Mac developers are expected to do:

You can verify your receipt validation code is compatible with the renewed certificate in the test and production environments. A pre-release version of the Mac App Store Update for OS X Snow Leopard beta is now available.

The linked “pre-release version” was no-doubt once a valid link, but at least through my account, it now leads to a permission-denied type failure page.

So what do we do? Fortunately, after chatting through the problem with some friends, Chris Liscio deduced the key, somewhat-obvious in retrospect steps to test your Mac app for compliance with the new certificate, while getting sandbox testing working again at the same time:

  1. Install the new certificate from Apple. In my case, I opened it in Keychain access and added it to the System keychain, where the older, expiring certificate currently resides.
  2. Reboot.

The second step is the important one. If you just install the certificate and expect everything to work, you’ll be sadly rebuffed with continued failures. Reboot. Let the system soak in the new certificate, then try re-launching your Mac app built for submission to the Mac App Store. It will prompt you, as you had previously expected it to, for your sandbox credentials. When you enter them, instead of insisting you set up a new iTunes customer profile, it will just launch. Or, if it doesn’t, maybe you’ve got some problems to work though in your receipt validation code.

Presenting HTML On Apple TV

In a recent post on my Bitsplitting blog, I complained that Apple’s forbiddance of web views on Apple TV would limit many developers who use HTML tastefully in the construction of their interfaces. I suggested that Apple might allow developers to use web views, but limit their usefulness as full-fledged web browsers.

Since writing that article, I discovered a potentially useful “backdoor” of sorts that could allow developers to continue using HTML to some extent for visual formatting of content in their user interfaces.

UITextView supports attributed strings, and NSAttributedString supports being initialized with HTML. Historically on the Mac at least, this capability was famously poor, but I seem to recall reading that it had been boosted at some point by using WebKit behind the scenes to do a more proper conversion.

Here’s an example of how an Apple TV app can convert literal HTML content into a visual form. This is, so far as I can tell, compliant with both the letter and the spirit of Apple’s guidelines for using the SDK:

NSString* staticHTMLContent = @"<div style='font-size:6em;'><strong>Hello</strong> <span style='font-family:courier;'>there</span>, I'm <span style='color:red;'>HTML</span>!</div>";

NSAttributedString* myHTMLString = [[NSAttributedString alloc] initWithData:[staticHTMLContent dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType} documentAttributes:nil error:nil];

[self.textView setAttributedText:myHTMLString];

This example code is run from a UIViewController whose self.textView is an IBOutlet to a UITextView in the user interface. And here’s how it looks in the Apple TV simulator:

HTML rendered on the Apple TV simulator

Granted, this is a far cry from a fully-functional web view. I’m sure it won’t serve the needs of all developers who currently rely upon UIWebView or WKWebView, but I expect that in some cases it will be a valuable workaround to the otherwise total omission of support for rendering HTML on Apple TV.

NSURLSession Authentication Challenge Disparity

Thanks to a bunch of my networking-related unit tests failing on 10.11, I came to the conclusion that NSURLSession’s authentication challenge mechanism changed from 10.11 with respect to the way HTTP Basic Auth challenges are handled.

In 10.10 a data task that is created for a resource protected by HTTP Basic Auth will result in a callback whose protection space method is identified as “NSURLAuthenticationMethodDefault”, while in 10.11 the same code accessing the same resource yields a protection space method “NSURLAuthenticationMethodHTTPBasic”.

The problem here is that existing challenge-handling code may have been written to handle the 10.10 behavior, looking for HTTP Basic Auth challenges like this:

if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault)
{
	// Handle the challenge
	...
}

While on 10.11 the “Handle the challenge” code will never be reached, so this shipping code will fail to function.

I think a robust workaround (that unfortunately requires re-compiling and re-shipping) is to test HTTP authentication challenges for either NSURLAuthenticationMethodDefault or NSURLAuthenticationMethodHTTPBasic, and treat them both as equivalent.

I filed this as Radar #21918904, and wrote a message in the developer forums in case people want to discuss the issue or the merits of various workarounds.

WebKit Hacking From The Bleeding Edge

As the developer of an app that depends heavily upon Apple’s WebKit technologies, I have often been grateful that the software is open source. It is by no means easy to wrap one’s head around, but when faced with a vexing problem, I can browse, even build and run a custom copy of WebKit on my system, to step through code and try to reason more clearly about its behavior. I’ve even filed my share of bug reports and patches.

While I am very interested in the evolution of WebKit, I am even more concerned with the evolution of OS X. For this reason, I typically install OS X beta releases far earlier than many of my colleagues. This gives me the opportunity to work day to day with the latest changes coming from Apple, and makes it that much more likely I will spot issues with my apps, concerns with the OS, etc., before my customers do.

As an open source project, I initially believed I could build and run WebKit wherever I choose. After all, isn’t that what “open source” is supposed to be all about? But ah, there’s a catch. At least when it comes to building and running WebKit on OS X releases, there is a dependency on a small, binary-only static library which provides key system-specific linkages to WebKit. Usually this binary is added to the open source project around the time the system release goes public, but not much sooner.

The long and short of it? If you want to build WebKit and you don’t work at Apple, you need to do so from publicly released versions of OS X.

For years, I have found this personally annoying, but also philosophically distasteful. It seems like a problem for Apple, too: it’s in their best interest to have as many WebKit developers as possible staying up to date, building the latest versions, testing, submitting patches, etc. And it’s in their interest to have as many OS X developers running the latest betas of the OS, providing feedback, preparing their apps for the public, etc.

A single developer, with a single Mac, running a single installation of OS X cannot simultaneously be a diligent, interested WebKit developer and a dedicated OS X beta tester. This seems like a problem to me, so I finally reported a bug. Radar 21703162: “Beta OS X releases should facilicate building/running WebKit from source.”

Predictable Date Formatting

Note: see caveats at the bottom of this post. Some of my conclusions in the body of this post are wrong and motivated by a misunderstanding of NSDateFormatter’s documented behavior. I’m leaving the post here for reference because I still think it could help somebody trying to understand similar behavior in their own app, but don’t take the griping too seriously…


Apple’s NSDateFormatter class supports a method of converting a date to a string by use of a date format string. For example, the date format string I use in MarsEdit to supply dates in ISO8601 format to blog servers:

@"yyyyMMdd'T'HH:mm:ss'Z'"

That “HH” is supposed to reflect the hour as a zero-padded number between 00 and 23. And it does, or at least it has, ever since I started using this formatting string in MarsEdit eight years ago.

Starting very recently, I think with 10.10.3 (Edit: nope, not new after all, see end of post), NSDateFormatter may return a string formatted for the user’s 12-hour clock preference, and with a troubling “am” or “pm” component embedded within. So instead of a bona fide standard ISO 8601 date for the above format, MarsEdit is now prone to receive something like this:

20150526T1:58:42 pmZ

Oops! And Ugh! The whole point of using NSDateFormatter’s dateFormat string, I thought, was to specifically generate strings that defy the user’s preferences, but that comply with a very specific set of rules. In fact, Apple encourages using date format strings in their documentation:

There are broadly speaking two situations in which you need to use custom formats:

	1. For fixed format strings, like Internet dates.
	2. For user-visible elements that don’t match any of the existing styles

Yes, internet dates! Thank you. Well, no thanks, I guess. The current documentation also goes on to offer some caveats, particularly with respect to iOS, where I guess users have been empowered to override the 12/24-hour clock setting for longer than they have on the Mac. And in general, they warn:

Although in principle a format string specifies a fixed format, by default NSDateFormatter still takes the user’s preferences (including the locale setting) into account.

The specific scenario where this crops up for me is if the user has set their Mac’s region to one that defaults to 24-hour time, but has then specifically chosen to uncheck the 24-hour time option:

Language Region

The behavior doesn’t occur, for example, if the user’s region defaults to 12-hour time as it does in the United States. It only occurs when a region’s defaults have been specifically overridden.

If you want predictable behavior from NSDateFormatter, you must set an explicit NSLocale on the formatter before requesting any string generation. I’m not sure it matters which locale you set, the key seems to be setting it to anything but the default to avoid this strange deference to the user’s default settings.

I’ll be fixing this by setting the locale on the NSDateFormatter to “en_US” because, being the very locale that my Mac is most often configured to use, I’ll be more likely to notice if the workaround stops working at some point in the future. I reported a bug (Radar 21105874) because it seems to be there should be a more straight-forward means of expressing to NSDateFormatter that you want to perform a very literal conversion, one that is guaranteed to not take into consideration any user-provided customizations of date and time formatting.

Hopefully this post will help other developers notice and repair the faulty handling of date strings in their apps, before too many of your customers run into the problem first!


Update: Many thanks to several people on Twitter noting that Apple specifically recommends using the “en_US_POSIX” locale for this purpose. I am still a bit annoyed that the behavior changed out from under me, but it sounds like setting the locale explicitly to this computer-y locale is the right solution for the long term.

Update 2: Well I made a few wrong assumptions before writing this post. After further testing I’ve confirmed the problematic “new” behavior is at least the case in 10.9.4 and possibly earlier as well. I’m now inclined to think this has been my bug all along, but I still think I’ll file a bug with Apple encouraging them to update the documentation to stress that setting a locale on the formatter is important.

Update 3: It turns out the documentation goes into some detail about the need to specify a locale, but I overlooked it because it was in a section about “parsing date strings” (not what I’m doing here). I filed Radar 21115452, requesting better documentation about the need to set a locale in the section pertinent to either parsing strings or generating them.

Storyboard To Nib And Back

At some point along the way Xcode has consolidated the “Main Storyboard” and “Main Interface” fields pertaining to storyboard and nib files into a single “Main Interface” field that simply updates whichever of the pertinent Info.plist fields Xcode thinks you are working with.

The problem is that if you switch from storyboard to nib or back, then the value of the Info.plist entry is changed, but the key is not updated to reflect whether the new value is either a storyboard or a nib.

I’ve reported Radar 20954053 to Apple, requesting that Xcode should intuit from the file extension of the file named by “Main Interface” whether the Info.plist should advertise a storyboard or a nib.

In the mean time, if you switch from storyboard to nib or back, you need to manually update the Info.plist key to match: UIMainStoryboardFile if you’re using storyboards, or NSMainNibFile if you’re using nibs.