Monthly Archives: June 2016

Swifty SDK Changes

I’m not quite ready to leap to Swift 3.0, so when the Xcode 8 beta asked me to migrate my existing Swift code, I opted to switch to Swift 2.3.

Swift 2.3 is notable for its utter dearth of new behaviors, compared to Swift 2.2.1. Since no code changes are required, you should be able to opt in to 2.3 on Xcode 8, while continuing to build and distribute with Swift 2.2.1 on Xcode 7.

On the other hand, you may run into some system SDK changes that force you to accommodate distinctions between, for example, the macOS 10.11 and 10.12 SDKs. Here’s an example of a build failure I ran into when I set to building my app on Xcode 8:

Image of Xcode exhibiting a build-time error because of a Swift method call

“invalid use of ‘()’ to call a value of non-function type ‘Selector'”

What does it mean? It means that in the 10.11 SDK, “action” is defined as a method:

@protocol NSValidatedUserInterfaceItem
- (nullable SEL)action;
- (NSInteger)tag;
@end

While in the 10.12 SDK, it’s been upgraded to a property:

@protocol NSValidatedUserInterfaceItem
@property (readonly, nullable) SEL action;
@property (readonly) NSInteger tag;
@end

Objective-C doesn’t care whether you access the value as a property, or by invoking the method that implements the property. Swift … does.

So, the fix in Xcode 8, with the 10.12 SDK, is to delete those parentheses so Swift appreciates that it’s accessing a property. But doing so will break the build back on the 10.11 SDK. What’s a forward-looking, backward-looking developer to do? You might think you could take advantage of Swift’s #available operator, and that in fact best expresses what we’re trying to do: to behave differently depending on the specific SDK that is being used:

if #available(OSX 10.12, *) {
	thisAction = anObject.action
}
else {
	thisAction = anObject.action()
}

But this still produces a build error, because Swift compiles both code paths of an #available block. Unfortunately, I think the only way to convince Swift to absolutely ignore the problematic line is to use a Swift compiler check, instead. Note that this is a bad solution because we are fundamentally not concerned about the version of Swift being used. If Swift 2.3 were made available in Xcode 7, against earlier SDKs, then the logic of our test would fail:

#if swift(>=2.3)
	thisAction = anObject.action
#else
	thisAction = anObject.action()
#endif

In my opinion, we need a compile time, conditional code exclusion that operates on the SDK, similarly to #available. Something like “#if sdk(OSX 10.12)”. As far as I know, nothing like this exists.

I’ll report a bug to Apple requesting such functionality, but I wonder if I’m overlooking something obvious that already fits the bill. Any ideas?

Update: Radar #26895983.

Dynamic Development Team

The first Xcode 8 beta was released at WWDC, and includes a major revision to the way code signing is handled by default. You can watch the video or read the slides on Apple’s WWDC Videos page.

A major change from Xcode 7 is that Xcode now requires that every target in your project specify a development team, even when the manual code signing option is selected.

This is a nuisance to developers who have fine-tuned their code signing process such that signing is configured elsewhere: for example, in a centralized Xcode configuration file that imparts signing information to all projects in an organization.

The problem is worse for open source projects, where a project may be expected to be checked out and built by a variety of organizations. In this scenario, each organization will have to somehow automate the insertion of a valid team name and ID in the project file after every checkout or update.

The DevelopmentTeam and DevelopmentTeamName values are stored in the Xcode project file, so they can’t be defined in Xcode configuration files the way so many other settings that affect build behaviors can.

Xcode needs some mechanism for providing these values without manually, permanently altering the affected project files. I would welcome either a mechanism for specifying the values in the Xcode configuration file specified for the project, or a wildcard type value that can be selected to indicate the “default team” should be used.

(Radar #26892618)

Update: It turns out my wishes are already answered. The new PROVISIONING_PROFILE_SPECIFIER build setting will impart the desired team information to Xcode, even if provisioning profiles are not used. So, something like this in my Xcode configuration file:

PROVISIONING_PROFILE_SPECIFIER = 493CVA9A35/

Quiets all of Xcode’s gripes about requiring a team name, and doesn’t require that I tediously update every last target with explicit team information. This doesn’t exactly solve the challenge for open source projects, because organizations using an open source project will still have to override the configuration file or build settings for the projects they check out. As far as I know there is no way to define PROVISIONING_PROFILE_SPECIFIER generically, the way you can specify code signing identities as e.g. “Mac Developer”. It would be great if open source projects could declare a PROVISIONING_PROFILE_SPECIFIER (when needed) as:

PROVISIONING_PROFILE_SPECIFIER = Automatic/

And allow the host project’s prevailing team identity automatically apply. But, I am satisfied to know this at least doesn’t need to be manually set everywhere in order to continue building my projects successfully.

Nullable Edge Cases

I’ve recently embarked on the tedious process of annotating my source code for nullability. This is a good idea in theory, because it adds information about assumptions in your code, which may have been previously held in arcane comments, or worse yet your mind, in a format that can be readily understood by the compiler. If you’re bridging your Objective C to Swift, the idea goes from good to essential, as the nullability information is critical to Swift working safely with your existing classes.

Does nil make sense here or not? If you decide to take on this task, you’ll ask yourself that question again, and again, and again. It sounds like such an easy thing to answer, and it certainly is in many cases, but the edge cases are deeply tied to one of several impedance mismatches between Objective C and Swift.

The easiest answers apply to methods where you can state with absolute certainty that programmers should never pass nil as a method. For example, I’m confident in annotating this method’s single parameter nonnull because the functionality of the method would be inherently undefined were a nil value supplied:

- (void) presentMessageToUser:(NSString*)theMessage;

The implications of marking a method parameter as nonnull are less worrisome than marking a return value, at least with respect to bridging the gap between Swift and Objective C. Because a method parameter will almost always represent the mapping of a Swift variable into Objective C, where handling of nil is traditionally safer, it doesn’t matter as much if a Swift variable passed to a nonnull Objective C parameter actually an optional. Marking method parameters optimistically nonnull is a fairly safe move.

Marking return values accurately is more important, because it maps possibly null values into Swift variable classes that won’t allow it. The annotation of a return value can be very straightforward, if inspection of the method indicates a 100% likelihood of a null response:

- (NSString*) importantString
{
	NSLog(@"Not implemented! Subclass responsibility.");
	return nil;
}

Or a nonnull one:

- (NSString*) errorMessage
{
	return @"Welp!";
}

For this method to return nil, the statically allocated string that the compiler creates and compiles into your binary would have to somehow turn to nil at runtime. If this were to somehow occur, you’d be facing much worse problems than the nonnull method managing to return nil.

It’s only slightly more complicated when the code path for a method can be audited to a degree that a nil result seems exceedingly unlikely:

- (NSString*) localizedErrorMessage
{
	return NSLocalizedString(@"Welp!", @"Error message of last resort");
}

For this method to return nil, NSLocalizedString, which is a macro that maps to -[NSBundle localizedStringForKey:value:table:], would have to return nil. This method is not only annotated by Apple as nonnull, but supported in its documentation as returning sensible, nonnull values in error cases:

This method returns the following when key is nil or not found in table:

  • If key is nil and value is nil, returns an empty string.
  • If key is nil and value is non-nil, returns value.
  • If key is not found and value is nil or an empty string, returns key.

So, any method whose return value is derived from a nonnull method, can also be annotated as nonnull. Right? Yes, for the most part.

The question of whether a method should return nil vs. whether it may return nil gets very fuzzy around the edges, owing to Objective C’s traditionally very nil-friendly (some might say nil-happy) programming paradigm. Let’s take a core method, one of the most fundamental in all of Objective C, the NSObject init method. Barring an override in any Objective C class, this method will be used to initialize and return a usable instance of any just-allocated class:

- (instancetype) init;

But is it nullable? In practice, NSObject’s root implementation, at least, should never return nil. It’s safer even than -[NSObject alloc], which should also never return nil, but theoretically could if you for example had completely exhausted virtual memory. Want to absolutely convince yourself that -[NSObject init] cannot return nil? Break in the debugger and examine its disassembly:

libobjc.A.dylib`-[NSObject init]:
    0x7fff8909ebf0 <+0>:  pushq  %rbp
    0x7fff8909ebf1 <+1>:  movq   %rsp, %rbp
    0x7fff8909ebf4 <+4>:  movq   %rdi, %rax
    0x7fff8909ebf7 <+7>:  popq   %rbp
    0x7fff8909ebf8 <+8>:  retq   

To summarize the behavior of this simple method, literally all it does, apart from the probably unnecessary stack-manipulating boilerplate, is to move the parameter in register %rdi (the first parameter to objc_msgSend, the object instnace itself) to register %rax (the return value of the method). It’s just “return self”, and self has to be nonnull or else this method wouldn’t have been reached.

Yet if you examine the objc/NSObject.h header file, where -[NSObject init] is declared, you’ll find something curious: it’s not annotated for nullability at all. And although I showed by disassembly above that it is guaranteed 100% to be nonnull, here’s what Apple’s own documentation says:

Return Value
An initialized object, or nil if an object could not be created for some reason that would not result in an exception.

Although this is declared on the documentation for NSObject, it’s no doubt based on the Cocoa convention that any class’s own particular -init method may and in fact should return nil if it cannot be initialized:

In a custom implementation of this method, you must invoke super’s designated initializer then initialize and return the new object. If the new object can’t be initialized, the method should return nil.

NSObject’s init method is one example of many situations in Objective C where nil is an expected return value in edge cases, but where as a general rule, a nonnull value will be returned. This is at huge odds with Swift’s emphasis on variable values being either nonnull or nullable by design.

In recent Xcode releases, Apple has added a useful clang analysis option, off by default, called CLANG_ANALYZER_NONNULL. When enabled, the analyzer goes the extra mile identifying situations where your code contains paths that will violate the spirit of your nonnull annotations. This has been very useful to me in identifying some spots where I missed a nuanced behavior of a method when adding nullability annotations. However, it also identifies a lot of defensive coding techniques that I’m frankly not prepared to abandon. The Objective C, it is strong in my family. Here is an example of a category class method I’ve defined on NSImage (explicit nonnull annotations added for emphasis):

+ (nonnull NSImage*) rsImageWithCGImage:(nonnull CGImageRef)srcImage
{
	NSImage *newImage = nil;
	if (srcImage != NULL)
	{
		NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:srcImage];
		if (bitmapImageRep != nil)
		{
			newImage = [[NSImage alloc] init];
			[newImage addRepresentation:bitmapImageRep];
		}
	}

	return newImage;
}

Clang analysis rightly reveals that although I’ve marked this method as having both a nonnull parameter and a nonnull result, the implementation of the method behaves otherwise. But this method is exceedingly unlikely to return nil. The srcImage parameter is marked nonnull, so that first line of defense should always be breached, and the -[NSBitmapImageRep initWithCGImage:] is so likely to return a nonnull value, it is annotated as nonnull (even though the documentation claims it may return nil, Radar #26621826).

I struggle with methods like these: do I mark them optimistically as nonnull, or do I suck it up and concede that they may in fact return nil? Do I remove the defensive checks for nil that I’m so accustomed to, and migrate to the Swift-style assumption that nonnull values will be as they say they will? I clearly have trust issues.

The consequences of vending a null value to a Swift non-optional are dire: the app crashes immediately either unwrapping an implicitly unwrapped optional, or directly accessing a nonnull value. Because of this, I think that in annotating Objective C code for nullability, one must err heavily towards marking return values as nullable, even if such a result is unlikely. How heavily will I err? Will I assume that every -init method may return nil, as indeed Apple has documented? I … well, no. That way lies madness. But wherever I felt compelled to put up overt safeguards in Objective C to handle possible nils from Apple’s frameworks, there is probably still cause for skepticism, even if the method has been marked as nonnull.

The down side of course is that my Swift code will have to jump through mostly unnecessary optional chaining, or other protections, to work safely with what is 99.9% guaranteed to be safe. But in the rare instances where nil is returned, especially when the circumstances that lead to it are out of my control in Apple’s own frameworks, I’d rather my Swift code behave a little bit more like my beloved old Objective C code, and fail gracefully on null.