Monthly Archives: May 2016

Implicitly Crashing Optionals

If you’re an old-time Objective C programmer like me, your first effort to add a Swift file to your project will be met with a cheerful offer from Xcode to “add a bridging header.” This header accommodates the Swift compiler generating Swift interfaces for all the existing Objective C classes you’ll no doubt want to interface with.

At first, I didn’t think too much of this bridging header. Sure, I want to access my Objective C files from Swift. Which ones? Why not all of them?

Life goes on, and as you proceed to write more and more Swift files, you’ll inevitably come to a point where your app crashes because an “implicitly unwrapped optional” turns out to be nil. What happened?

If you’re like me and you haven’t gotten around to annotating all your Objective C headers with nullability tags, Swift imports almost every pointer type as an implicitly unwrapped optional. This means it will be treated as a value that can be nil but is never expected to be nil by the time you access it.

This stuff is all well-covered in Apple’s documentation, but I have never been one to jump straight to RTFM. :)

My takeaway is to accept that it is fundamentally unsafe to interface with Objective C classes whose headers have not been audited for nullability. So back to that bridging header… 

I now impose a rule for my Objective C -> Swift bridging header that any import added to the file must first be confirmed as audited for nullability. If it’s not audited yet, I commence with the somewhat tedious task of annotating (with the help of NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END, of course) the entire header file, sometimes searching the correlated source files to confirm assumptions about nullability of parameters. When I’m done, I can (relatively) safely import the header into Swift and count on appropriate optional type checking. Except…

In addition to the imported header, of course, I need to audit any headers that the header itself imports. So if there’s some secondary class that works in conjunction with the main class, and whose header is also incorporated into the header, I have to go annotate that class for nullability, too. Here is an opportunity to take stock of whether you really need to import such a class. For example, it might be that a forward declaration will do, and the implementation (.m) file can import the header for internal use only.

Failing to recognize the importance of nullability annotation was probably my biggest mistake yet in my young Swift career. If you’re just getting started tackling Swift from a legacy Objective C source base, here’s hoping you won’t make the same mistake!

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.

Scripted Swift Warnings

Since I complained yesterday about Swift’s lack of a counterpart to Objective C’s #warning directive, folks have been in touch to encourage another solution to this problem. I could take advantage of Xcode’s standardized, built-in support for text-based comments such as “// FIXME” and “// TODO”. Using this notation causes the affected source lines to show up in Xcode’s per-file function popup, and other folks affected by the issue I describe above have added scripted build phases to emit text that Xcode will treat as a warning for each of these lines.

I initially dismissed the solution out of hand, because I anticipated that searching all of my sources with every build would be excessive. I’m kind of a stickler for fast build times because I like to do quick iterations when writing and testing code. My largest source base, MarsEdit, is big but not huge. But, appreciating that computers and SSDs are fast, I decided to test the straightforward script linked above to see how much time it would add to each of my build iterations. On average, it’s about 1.2s per build. It doesn’t sound like much, but personally that would nag at me. I’ve made a fuss over build phase speeds in the past, and reported bugs against unnecessary slowdowns in Apple’s standard build phases.

Zev Eisenberg suggested on Twitter that the use of specialized search tools such as the_silver_searcher might help. It’s true, it might, but then I’d be going down a path of installing custom software, writing custom scripts, all to accommodate what is a very useful feature that I personally still believe should be built in to the language. Or, at the very least, the language’s feature set should accommodate efficiently extending it to support something like #warning.

We’ll see where things go. I may yet end up adopting a convoluted (to my mind) approach involving expensive, redundant build phase script that scans my entire source base with every build, but more likely I’ll keep scratching my head while using the one-line, inline hack that I previously described.

Artificial Swift Warnings

I’ve been tackling more and more of my coding challenges in Swift, recently. I’ve run into a number of hangups. Some attributable to the learning curve, some to bugs in Swift or Xcode, and some to features I’ve grown to love in clang and Objective C which are simply not present in Swift.

For years, I’ve been in the habit of tagging my in-progress code with “artificial warnings.” While working in code, if a concern crosses my mind, the easiest way to make sure I won’t ship the software without addressing that concern is to add it directly to the code:

#warning Step through this in a debugger and confirm it still works...

Or:

#warning This isn't implemented yet, need to handle XYZ...

These warnings serve as an active reminder of things to fix while I’m working in Xcode, since they show up in the build navigator, and are illuminated in the source code while stepping through with the debugger. And because of my strict “no warnings” policy for shipping code, they are guaranteed to show up as errors in any Release build, thus thwarting an accidental shipment of code that is known to need further refinement.

I don’t think Swift supports anything like the “#warning” preprocessor directive.

The closest I’ve come to matching this behavior is a trick that employs Swift’s willingness to emit a warning for unreachable code:

if false { "in lieu of #warning, this will do" }

Unfortunately, it only shows up in the issue navigator as “Will never be executed,” and doesn’t show the specific warning text contained in the string. But at least as soon as click on the warning, I am reminded of the concern at hand.

I don’t know if the Swift team is philosophically opposed to implementing support for #warning, or something like it. I filed an enhancement request with the Swift project. In the meantime, if false { “life goes on.” }.

Update: Many folks have suggested a build-phase script to tag warnings. I wrote more about that option in a followup post.

A Tale Of Two Optimizers

I have quipped a few times that my biggest problems with Swift so far have to do with struggles in the debugger. It seems slow, inaccurate, harder to use than in Objective C. Some of this is just a learning curve, but other aspects seemed fundamentally broken. I whined on Twitter about a scenario in which lldb seemed utterly unaware of one of my variables:

A kind Apple employee, Kate Stone, followed up with me and ultimately encouraged me to file a bug:

I obliged, filing Radar #26032843. Today, Apple got back to me with a followup, suggesting rather gently that I may have neglected to disable optimization in my target. Rookie move! The kind of behavior I was seeing in the debugger is exactly what happens when lldb can’t make as much sense of your code because of inlined functions, loops that have been restructured, etc.

In fact, I had correlated the symptoms with such a problem, but when I went to check on the status of my optimization settings, everything looked fine. Why? Because I was looking, by habit, at the Clang LLVM “Code Generation” settings for optimization:

MarsEdit xcodeproj

See? Optimization disabled. Just as it is for all my projects, and all my targets, because I define it once in my centralized Debug “.xcconfig” file, to be sure I never screw it up:

// We only specify an optimization setting for Debug builds.
// We rely upon Apple's default settings to produce reasonable
// choices for Release builds
GCC_OPTIMIZATION_LEVEL = 0

So why does debugging Swift fail so hard for me? Because Swift doesn’t use that optimization setting. Scrolling down a little farther, I find the culprit in Swift’s own compiler settings section:

MarsEdit xcodeproj

So the lesson is that new Swift developers coming from a legacy of Objective C, C++, or C development need to take stock of Swift compiler settings because they are liable to be rooted in completely different build settings. On the one hand, I’m glad Apple is finally able to get away from a build setting like “GCC_OPTIMIZATION_LEVEL” (though keeping the name in the GCC -> LLVM transition prevented problems like this back then), but on the other hand, it’s kind of annoying to have to express high level directives that affect whether my code will be debuggable or not using multiple build settings.

At least, because I am not an animal, this will also only ever need to be done once, with an edit to the pertinent “.xcconfig” file:

// We only specify an optimization setting for Debug builds, we rely upon
// Apple's default settings to produce reasonable choices for Release builds
GCC_OPTIMIZATION_LEVEL = 0
SWIFT_OPTIMIZATION_LEVEL = -Onone

Now if you’ll excuse me I’m going to take a tour of other Swift-specific compiler settings to make sure I’m not shooting myself in the foot in some other way!

Pasteboard Priority

A weird bug cropped up in MarsEdit, in which a URL copied and pasted from Safari, for example, was pasting into the plain text editor as the text from the link instead of the link itself. Daring Fireball’s star glyph permalinks to entries presented a most dramatic example. Right-clicking a star glyph and copying the link to paste into MarsEdit was supposed to yield:

Image of pasted link shown as expected with full text content of URL

But instead gave:

Image of pasted URL showing the text of the link instead of the URL content

How strange. What could have possibly changed something so fundamental as the manner in which a pasted link is processed by my text editor? I leaned on Mercurial’s “bisect” command which led me to the specific source code commit where the behavior had changed, in my text view’s helper method for building a list of acceptable paste types. My color emphasis is on the changed part:

-	return [[NSArray arrayWithObject:NSFilenamesPboardType] arrayByAddingObjectsFromArray:[NSImage imageFileTypes]];
+	return [[NSArray arrayWithObject:NSFilenamesPboardType] arrayByAddingObjectsFromArray:[NSImage imageTypes]];

That’s it? One little tweak to the construction of a list of image types affects the behavior of pasting a URL copied from Safari? Programming is hard.

I had made the change above because imageFileTypes is deprecated. The deprecation warning specifically says: “use imageTypes instead.” Okay. Functionally, everything related to the image types should work the same. Instead of a list of file extensions from -imageFileTypes, I’m now getting a list of UTIs. I scrutinized the lists a bit to satisfy myself that all of the major image types were present in the new list, and I trust that Apple had covered the bases when they made this migration themselves.

It turns out the change above, the one word diff that causes everything to work either as expected or otherwise, is fine. It’s outside of this method where the real problem lies: in my override of NSTextView’s -readablePasteboardTypes method. In it, I endeavor to combine my own list of pasteable types with NSTextView’s own list. To do this, I create a mutable set to combine -[super readablePasteboardTypes] and my own list, and then return an array of the result. The idea is to avoid listing any items redundantly from the built in list and my own:

- (NSArray*) readablePasteboardTypes
{
	NSMutableSet* allReadableTypes = [NSMutableSet setWithArray:[super readablePasteboardTypes]];
	[allReadableTypes addObjectsFromArray:[self acceptableDragTypes]];
	return [allReadableTypes allObjects];
}

Ah, my spidey sense is finally starting to tingle. While it’s not mentioned in the NSTextView reference documentation, the NSTextView.h header file includes comments about this method that are pertinent here:

Returns an array of types that could be read currently in order of preference.  Subclassers should take care to consider the "preferred" part of the semantics of this method.

Ah, so order matters. Of course. And what does the -[NSSet allObjects] say about order?

The order of the objects in the array is undefined.

So all this time, I’ve been playing fast and loose with NSSet, lucking out with the coincidence that types I prefer would show up higher in the list than types I don’t prefer. It turns out that “public.url” is among the types included in NSTextView’s own, built-in readablePasteboardTypes method implementation, but previous to this change, it always showed up lower in resulting list than NSStringPboardType. Thus, when faced with an opportunity to paste a URL from Safari, rich with information including the original text from the link, MarsEdit always favored the plain string representation.

Changing from -[NSImage imageFileTypes] to -[NSImage imageTypes] effectively changed the roll of the dice, causing the resulting array from NSSet, documented as being “undefined” in its order, to place the URL type above the string type in the list. Thus it tries to paste as a rich URL with text linking to a URL, but since my plain text HTML editor doesn’t support rich text, all you see is the star.

The fix will be to arrange that my resulting array from readablePasteboardTypes does impose some predictable prioritization. Probably by taking the code that I have now and, after generating the list of all unique types, carefully moving a few types to the top of the list in the order that I’d prefer.