All posts by Daniel Jalkut

Unsteady Platform

I ran into a vexing build failure with one of my iOS integration builds. The vast majority of everything in my complex project, consisting of dozens of dependencies, has built fine, but at link time things blow up because one of the dependencies is not of the expected architecture.

Undefined symbols for architecture armv7:
"_RSIsEmpty", referenced from:
-[RSFormattingMacro emptyMarkupPlaceholders] in RSFormattingMacro.o
ld: symbol(s) not found for architecture armv7

Ugh, huh, wha? How is this happening? It turns out the library in which “RSIsEmpty” resides, RSFoundation, is being linked to, but it’s opting for an OS X version of the library instead of an iOS one. Because this is an integration build that performs a number of related builds for both Mac and iOS, it makes some sense that I would have both an iOS and OS X build result in the build folder. But even if I have built copies for either architecture, why is it opting for the OS X version on an iOS build?

I decided to blow away all the built versions of RSFoundation and try the build again. This time, I got an even more perplexing failure:

clang: error: no such file or directory: '[...]/build-Integration/Release/RSFoundation.framework/RSFoundation'

I’m scratching my head. Did it somehow get removed as a dependency? But then I notice something subtle. It’s looking for the framework in the “Release” build folder, but for my iOS build it should be looking in “Release-iphoneos”. What the heck is going on?

In spite of the sole build target in this scheme being an iOS app, Xcode (actually xcodebuild) is opting to build this scheme with a default destination of OS X. I don’t know of a direct way to get xcodebuild to list the available destinations for a scheme, but I know that if you pass a bogus destination platform, it will do the honor of listing its impressions:

xcodebuild -destination "platform=xx" -scheme MyIPhoneApp

The requested device could not be found because no platform could be found for the requested platform name.

Available destinations for the "MyIPhoneApp" scheme:
		{ platform:OS X, arch:x86_64 }
		{ platform:iOS Simulator, id:6DF04FFC-1C8A-4745-8F8C-7369E9CBF8DB, OS:9.3, name:iPad 2 }
		[... every other iOS simulator on my Mac ...]

Aha! So it thinks my iPhone app is suitable for OS X. But why? After a great deal of experimentation and poking around, I discovered the root of the problem is summarized by this true statement:

If any target in a Scheme’s dependency tree targets OS X, then the scheme itself will also be considered to target OS X.

In retrospect, this explains the problem perfectly. I had recently added a subproject to my dependency tree that builds both an iOS and a Mac version of a library. That’s fine: it works pretty well these days to allow targets for differing platforms to coexist in the same project file. But each of these targets also shares a dependency on a single, legitimate OS X target: a helper tool used in the process of generating that project’s own source files.

This must be at least a relatively common scenario for iOS builds of certain complexity. Because the platform on which all iOS builds run is OS X, any helper tools that are compiled and used in the process of generating sources or otherwise processing build materials, must be built for OS X.

The workaround to my specific problem is to specify a platform explicitly on the command line. I can’t assume that because the scheme targets iOS, it will necessarily default to an iOS platform target. I consider this a bug, not only because it led to this difficult to diagnose build error, but because it has other ramifications such as the presentation in Xcode’s scheme popup for these projects a useless, distracting “My Mac” target which should never be selected for the schemes in question.

I filed this as Radar #24247701: A scheme whose target has dependencies on another platform shouldn’t “support” that platform.

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.

Not Available On tvOS

Along with many other Mac and iOS developers, I’m digging into Apple’s SDK for tvOS development. As announced in the special event yesterday, the SDK is based on iOS and will be very familiar to most Apple platform developers. There are, however, some differences: functionality from iOS frameworks that is not available on tvOS, as well as a handful of new frameworks specifically suited to the needs of “TV apps.”

A very notable absence is UIWebView. Black Pixel’s Daniel Pasco points out on Twitter that this will be a significant impediment to porting many iOS apps:

When I say UIWebView is absent, I should clarify that the class name is still present in the UIKit headers on the tvOS SDK, but it is marked with a new compiler availability attribute, __TVOS_PROHIBITED. This is handy because at least when you run up against the problem, you don’t have to fret about whether you simply neglected to link against the right framework. It’s there, it may or may not work, you just can’t use it.

In case it’s not obvious, you can use a massive search of the SDK’s header files to zero in on other such classes and methods that may be prohibited from use in TV apps:

grep -r TVOS_PROHIBITED UIKit.framework/Headers/*

(Note: it was brought to my attention that this search is purely academic because Apple has published a browsable list of API changes from iOS to tvOS.)

The results are a doozy! But many of the marked items simply wouldn’t make sense on Apple TV, like mucking with the UIStatusBar, are marked as prohibited. There are other tags too, such as __TVOS_UNAVAILABLE, which presumably denotes that technologies that Apple would like to provide but hasn’t yet, and __TVOS_DEPRECATED, which blessedly does not yet match any API provided in the tvOS SDK.

Take a look in the Availability.h header file for this and other interesting attribute definitions, including counterparts for OSX, iOS, and watchOS.

The Seven Stages of Swift

For all except the newest members of our Apple development community, the arrival of Swift is something that has to be reconciled against our previous and ongoing relationship with Objective-C. This handy reference will help to guide you through this journey. Where do you fall in the spectrum? How you will advance to the final stage?

Shock and Disbelief

Apple announced a new programming language? They didn’t. They couldn’t. This is not WWDC. That’s not Tim Cook. The world is upside down! Why is John Siracusa smiling?

Denial

Swift is not even a real programming language. I mean, it’s not replacing Objective-C. I mean, It’s not meant for real Cocoa programmers. I mean, it’s just Apple trying to satisfy those … weird programmers who like buzzwords! Objective-C is here to stay.

Anger

Oh crap, Swift is replacing Objective-C! Arrrrrrrggghhh! Why, Apple!? WTF? Where’s Objective-C 3.0? You’re killing Objective-C?! I love Objective-C. Die in a garbage collected fire!!!

Bargaining

I suppose Swift might be useful someday. Support for dynamic message dispatch is a start. If Apple gives me just one more Objective-C feature, I’ll give it a shot.

Guilt

Ugh. I should really start learning about Swift one of these days! What is wrong with me?

Depression

Who cares? I could learn Swift, but what’s the point? My Objective-C skills are useless. Dot notation won. I feel this inexplicable weight in my arms. Static types are hanging from my arms. I can’t move my arms. Our apps are all going to die someday.

Acceptance and Hope

Holy crap, Swift made this so easy! Maybe I like Swift? I mean, I still love Objective-C, but I don’t love love it. Maybe we needed a new language. Maybe we were aching for a new language. Maybe we needed more buzzwords.

I like buzzwords.

(Why is John Siracusa smiling?)

A Eulogy For Objective-C

I missed Aaron Hillegass’s talk at AltConf earlier this year, but was nudged to take a look at the transcript by Caro’s tweet today linking to the talk’s video page on Realm.

Although I’m 100% sure, based on experience, that Aaron’s talk is a pure delight to watch, I also appreciate that I could jump right in and read a transcript of the talk until I get a chance to watch it. Aaron gives a thought-provoking “eulogy” for Objective-C, in which he celebrates its parentage and its life thus far.

When a guy like Aaron Hillegass gives a history of Objective-C, and speaks to its strengths and weaknesses, you should hang on every word. He covers many of the features that distinguish the language, provides a context for when they were added, and gives examples of key technologies that are enabled by them. He is also aware of the tradeoffs some of these features demand:

Loose typing made a lot of things that were difficult in other languages much easier, or possible. It also made bugs that didn’t exist in other languages possible as well. And you embrace that as an Objective-C programmer. You’re like, “This is a language for smart, pedantic, uptight people, I’m going to be very careful and do the right thing when I’m typing in names.“

I love his hypothetical quote, and think it condenses the feeling a lot of us long-time Objective-C programmers have about the language. We welcome Swift in many respects, but it’s hard to let go of a language whose idiosyncrasies we’ve grown to love, hate, and ultimately make peace with.

The Curious Case Of Xcode’s Commit Message

Xcode has a behavior with its source code integration, wherein the pending commit message is persisted so that if you cancel a commit, and then go back to commit again later, the text you already typed is preserved.

This is a nice feature.

However, my friend Seth Dillingham lamented on Twitter that for some reason the persisted commit text on his Mac was crashing Xcode. Yikes. No problem, he just needed to find the persisted text and delete it. It should be in some Xcode preferences file, or maybe in ~/Library/Developer, or somewhere else sane like that, right? Right?

Wrong. A little snooping on my part reveals that Xcode saves this bit of text in just about the least likely place I would expect…

Most people consider the OS X pasteboard pretty monolithic, especially since it’s so easy by default to obliterate the contents of the default pasteboard by e.g. copying new text to overwrite the old. But there are in fact multiple default pasteboards in OS X. For example there is a general pasteboard for typical copy and paste, but a different pasteboard for dragging content from one place to another. This is a good thing, because we wouldn’t want a drag to obliterate the copied text we were about to paste.

Have you ever noticed that on OS X, when you search for some text in one app, and then switch to another app to use its “Find” functionality, the same search text is already present in the search field? Thank, or blame, the system standard “Find” pasteboard, which makes this possible.

There are also an endless number of possible custom pasteboards, named by the creator and used for whatever purpose they see fit. Usually this is to accommodate the movement of data within an app in such a way that it doesn’t muck up the standard system pasteboards. But Xcode uses it for something more akin to the “Find” pasteboard described above. They declare and use a whole custom pasteboard to store … drum roll please … the commit message.

If you use Xcode for Source Control, select “Commit…”, type something into the commit message text area, then cancel the commit. Now, from the Terminal:

echo "from AppKit import NSPasteboard\nprint NSPasteboard.pasteboardWithName_(\"IDESourceControlCommitMessagePasteboard\").stringForType_(\"IDESourceControlCommitMessagePboardType\")" | /usr/bin/python

There’s your commit message!

Now, let’s suppose you have run into the same bad luck as Seth, and need to clear out that commit message text to prevent Xcode crashing? NSPasteboard’s “releaseGlobally” method should do the trick:

echo "from AppKit import NSPasteboard\nNSPasteboard.pasteboardWithName_(\"IDESourceControlCommitMessagePasteboard\").releaseGlobally()" | /usr/bin/python

Now you know possibly a bit more about NSPasteboard on the Mac and probably a lot more about how Xcode persists its commit message text. I know I sure do!

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.

Swift Libraries Code Signing

I wrote last year about problems arising from Developer ID signed apps and their dependence upon an Apple “timestamp server” during the code signing phase. In the article, I describe a workaround for scenarios where the timestamp server is either down or there is no internet connection: disable the functionality by adding “–timestamp=none” to the OTHER_CODE_SIGN_FLAGS Xcode build setting.

Swift based apps currently install a complete copy of the Swift standard libraries in the built app’s bundle, and during this phase, Xcode implicitly signs the Swift libraries with whatever code signing identity is defined by the project and/or target. Unfortunately in doing so, it ignores the OTHER_CODE_SIGN_FLAGS build setting, removing the opportunity to finesse code signing of the Swift libraries in the way I described.

The long and short of it? You can’t build a Developer ID based Swift application when you’re offline. I discovered this recently when I dug into a Swift application in a jet, high above the Pacific. Hours of uninterrupted, focused development time lay before me, but I was met with this annoying build failure:

The timestamp service is not available.
*** error: Couldn't codesign [...]/My.app/Contents/Frameworks/libswiftCore.dylib: codesign failed with exit code 1
Command [...]/XcodeDefault.xctoolchain/usr/bin/swift-stdlib-tool failed with exit code 1

The workaround is to turn off code signing completely, or to switch to a Mac App Store code signing identity (which doesn’t rely upon the timestamp service feature of the code sign tool). I filed this bug as a Radar #21891588.

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.