Category Archives: iOS

Discoverable Key Commands

As I make progress on Black Ink for iOS, I have taken care to add keyboard shortcuts to make the app more usable on an iPad with external keyboard. One standard behavior of iPadOS is that when an app supports keyboard shortcuts, simply holding down the command key presents a nice heads-up display (HUD) with the list of shortcuts. For example, if you press the command key on the iPad home screen, you’ll see something like this:

Screenshot of prompt showing list of keyboard shortcuts on iPad.

This panel is supposed to appear automatically for any app that declares keyboard shortcuts using the UIKeyCommand interface of UIKit, which Black Ink does. I couldn’t figure out why the panel never appeared in the app. When the Command key is pressed, I confirmed that my puzzle view was the “first responder”, meaning it is the view that iOS should consult when building the list of key commands to show. What could possibly be going wrong?

Never being one to take the easy route when solving a problem, I found myself tracing the UIKit system code deep into the infrastructure that determines whether or not to show a panel or not. When the command key is held for a sufficiently long time, an internal timer expires and “-[UIKeyCommandDiscoverabilityHUD _HUDPopTimerFired:]” is reached. This method ends up calling a private “_performableKeyCommandsWithResponder:” method, which finally leads to some code that … asks each UIKeyCommand for its discoverabilityTitle, or as a backup, its title. Hmm, what is the discoverability title? Let’s look at the header for UIKeyCommmand:

// Creates an key command that will _not_ be discoverable in the UI.
+ (instancetype)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action;

// Key Commands with a discoverabilityTitle _will_ be discoverable in the UI.
+ (instancetype)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action discoverabilityTitle:(NSString *)discoverabilityTitle;

Face, meet palm.

When implementing support for keyboard shortcuts, I had leaned on code completion and went with the easiest option. The shortcuts worked, so what could go wrong? It turns out you have to declare a title for UIKeyCommand or the system won’t present a prompt to users about it. It makes sense, because what would it list as the explanation for what it does, if nothing is set on it?

After I added discoverability titles, everything looks as it should:

Screenshot of Black Ink for iOS showing a full list of keyboard shortcuts for puzzle navigation, etc.

Hopefully this will help others who are stuck trying to figure out why their app’s keyboard shortcuts aren’t showing up.

Casting Objective-C Message Sends

Mike Ash shares interesting news that the latest Xcode SDKs include a change to the function prototype of Objective-C’s msgSend family of functions. Where objc_msgSend was previously defined in terms of the couple of parameters it usually takes, and with the return type that it sometimes has, it is now declared as taking no parameters and returning no value:

OBJC_EXPORT void
objc_msgSend(void /* id self, SEL op, ... */ )

In practial terms, this will have an impact if you are still using direct objc_msgSend calls anywhere in your code. For example, imagine you have a “transformer” class that is capable of performing a variety of text manipulations on strings. You might have some code that derives a “SEL” programmatically and then messages the transformer to perform the action. Here’s a contrived example:

SEL tSEL = @selector(uppercaseString:);
NSString* upString = objc_msgSend(transformer, tSEL, lowString);

While that would have worked previously (apart from some ARC warnings), on the latest SDKs you’ll get a compile-time error on the objc_msgSend call:

Too many arguments to function call, expected 0, have 3

Obviously, you need to pass the arguments or the invocation will be useless, but how do you do it? Mike’s post has the advice:

Because it still has a function type, you can still cast it to a function pointer of the appropriate type and invoke it that way. This will work correctly as long as you get the types right.

As long as you get the types right … so, how does one do that? Mike includes an example of inline-casting objc_msgSend, but if you need to do this more than once in your code, I think a more elegant way of casting objc_msgSend is by declaring a global variable as a function pointer with the desired types:

#import "objc/message.h"

NSString* (*PerformWithStringReturningString)(id, SEL, NSString*) = (NSString* (*)(id, SEL, NSString*)) objc_msgSend;

Now when you want to invoke “objc_msgSend” on an object that you know accepts and returns a string type, you can do so like this:

NSString* upString = PerformWithStringReturningString(transformer, tSEL, lowString);

No compiler warnings, ARC knows just what to do with all the types, and you have a very clear understanding of what objc_msgSend is expected to do with this particular invocation.

Cryptic App Store Upload Error

I recently had cause to take another look at Swish, my iOS app for generating white noise and static visuals. OK, the reason was Apple sending me an email notification that, because it has been over three years since I last updated the app, they were going to remove it from the App Store in 30 days.

I had previously had it in mind to ship an update that supports the newest screen sizes for devices such as iPhone X, but I sort of lost track of that. This was a good motivation to get an other update out so I made a few quick improvements and set about uploading a build to Apple to “blow out the cobwebs” and see if I was missing anything else.

Upon uploading the app, I was met with this surprising error:

Screenshot of an error from Xcode indicating that \

The Info.plist indicates an iOS app, but submitting a pkg or mpkg.

Hmm. That’s weird. I’m not submitting a pkg or mpkg. At least, I don’t think I am. My Info.plist should indicate an iOS app, because Swish is an iOS app.

I racked my brain trying to figure out what was going on here, and finally ended up filing a bug to Apple. Luckily, they got back to me within a day or two with this unexpected advice:

Please remove the LSMinimumSystemVersion from the Info.plist.

I had added the “minimum system version” to the Info.plist because I decided this update would support only iOS 11 and higher. I didn’t understand why that value would have anything to do with my issue, but I dutifully followed their advice, submitted the app, and … it worked perfectly!

Doing a little research, I discovered that LSMinimumSystemVersion is for macOS only, and that the iOS counterpart is simply called MinimumOSVersion. But, here’s the catch: the Xcode build process generates and inserts that MinimumOSVersion plist entry automatically, based on the deployment target for your app.

I hope this helps some frustrated Mac developer who is simply following old habits, and makes the mistake of adding LSMinimumSystemVersion to their iOS app’s Info.plist. Remove it, and your App Store uploads should work again!

Let it Rip

In the latest Mojave public beta, I noticed a foreboding warning in the console when I build and run FastScripts, my macOS scripting utility:

FastScripts [...] is calling TIS/TSM in non-main thread environment, ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!!

Ruh-roh, that doesn’t sound good. Particularly with the emphasis of three, count them three, exclamation points! I better figure out what’s going on here. But how?

Sometimes when Apple adds a log message like this, they are kind enough to offer advice about what to do to alleviate the problem. Sometimes the advice implores that we stop using a deprecated method, or in a scenario like this, offers a symbolic breakpoint we might set to zero in on exactly where the offending code lies. For example, a quick survey of my open Console app reveals:

default	11:54:18.482226 -0400	com.apple.WebKit.WebContent	Set a breakpoint at SLSLogBreak to catch errors/faults as they are logged.

This particular warning doesn’t seem to apply to my app, but if it did, I would have something good to go on if I wanted to learn more. With the TIS/TSM warning, however, I have no idea where to go. Do I even use TIS/TSM? What is TSM?

I’ve worked on Apple platforms for long enough to know that TSM stands for Text Services Manager. However, I have also worked on these platforms long enough to forget whether I’ve actually used, or am still using, such a framework in my apps! When these kinds of warnings appear in the console, as many times as not they reflect imperfections in Apple’s own framework code. Is it something Apple’s doing, or something I’m doing, that’s triggering this message?

Ideally we could set a breakpoint on the very line of code that causes this console message to be printed. This can be surprisingly difficult though. There have always been a variety of logging mechanisms. Should you set the breakpoint on NSLog, os_log, printf, fprintf, or write? I could probably figure out a comprehensive method for catching anything that might write to the console, but am I even sure this console method is being generated in my app’s main process? There are a lot of variables here. (Hah! In this particular case, I ended up digging deeper and discovering it calls “CFLog”).

This is a scenario where combining lldb’s powerful “regular expression breakpoints” and “breakpoint commands” can help a great deal. Early in my app’s launch, before the warning messages are logged, I break in lldb and add a breakpoint:

(lldb) break set -r TIS|TSM.*

I’m banking on the likelihood that whatever function is leading to this warning contains the pertinent framework prefixes. It turns out to be a good bet:

Breakpoint 5: 634 locations.

I hit continue and let my app continue launching. Here’s the problem, though: those 634 breakpoint locations include quite a few that are getting hit on a regular basis, and for several consecutive breaks, none of them is triggering the warning message I’m concerned about. This is a situation where I prefer to “let it rip” and sort out the details later:

(lldb) break command add 5
Enter your debugger command(s).  Type 'DONE' to end.
> bt
> c
> DONE
(lldb) c
Process 16022 resuming

What this does is add a series of commands that will be run automatically by lldb whenever breakpoint 5 (the one I just set) is hit. This applies to any of the 634 locations that are associated with the regular expression I provided. When the breakpoint is hit, it will first invoke the “bt” command to print a backtrace of all the calls leading up to this call, and then it will invoke the “continue” command to keep running the app. After the app has run for a bit, I search the debugger console for “!!!” which I remembered from the original warning. Locating it, I simply scroll up to see the backtrace command that had most recently been invoked:

  thread #7, stop reason = breakpoint 5.568
    frame #0: 0x00007fff2cd520fd HIToolbox`TSMGetInputSourceProperty
    frame #1: 0x00000001003faef2 RSFoundation`-[RSKeyboardStatus update](self=0x00006000002b8c00, _cmd="update") at RSKeyboardStatus.m:56
    [...]

Command #2 'c' continued the target.
2018-08-14 12:15:40.326538-0400 FastScripts[16022:624168] pid(16022)/euid(501) is calling TIS/TSM in non-main thread environment, ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!! 

Sure enough, that’s my code. I’m calling TSM framework functions to handle key translation for FastScripts’s keyboard shortcut functionality, and I’m doing it (gasp!) from thread #7, which is certainly not the main thread. I oughta be ashamed…

But I’m proud, because I tracked down the root of the problem pretty efficiently using lldb’s fantastic breakpoint commands. Next time you’re at a loss for how or where something could possibly be happening, consider the possibility of setting a broad, regular expression based breakpoint, and a series of commands to help clarify what’s happening when those breakpoints are hit. Then? Let it rip!

Icon for File with UIKit

There’s a general consensus among many Mac and (mostly) iOS developers, that AppKit is “old and busted” and UIKit is “new and refined.” I am still fairly limited in my experience with UIKit, but in many ways I agree that in developing the framework, they left some of the more annoying baggage of AppKit behind. However, they also left off many conveniences that AppKit developers like myself have come to rely upon.

One of the easiest things in the world in AppKit is asking the framework for an image to represent a file’s icon. Say you’ve got a Swift source file handy and you want to show it in your app with an appropriate icon. It’s an easy one-liner on the Mac:

let swiftIcon = NSWorkspace.shared.icon(forFile: "/tmp/Test.swift")

Screenshot of Xcode showing code to request an icon from NSWorkspace.

On UIKit, as far as I can tell, it takes a bit more work. There is no UIWorkspace, which is probably fine, but there is also no UIImage.iconForFile, or similar method to make this quite as straightforward as it is on the Mac.

I came across “UIDocumentInteractionController” which seems to be the key to easily obtaining icons for arbitrary image types on iOS. After initializing it with a file URL, you can ask it for an array of icons, which it will reveal in order from smallest to largest. Tying this all together in an extension on UIImage, you could add a pretty handy helper method to your collection of code (sorry, one of these days I’ll get syntax highlighting working on this blog):

import UIKit

extension UIImage {
	public enum FileIconSize {
		case smallest
		case largest
	}

	public class func icon(forFileURL fileURL: URL, preferredSize: FileIconSize = .smallest) -> UIImage {
		let myInteractionController = UIDocumentInteractionController(url: fileURL)
		let allIcons = myInteractionController.icons

		// allIcons is guaranteed to have at least one image
		switch preferredSize {
		case .smallest: return allIcons.first!
		case .largest: return allIcons.last!
		}
	}
}

Now I’ve got basically the same functionality I had on AppKit:

Screenshot of invoking the helper method from code snippet above.

This is cool enough, but what’s even cooler is the UIKit method works on a URL irrespective of whether the underlying file actually exists! This, combined with the fact that a URL can be initialized with just about any String, means we can expand our icon utilities with a method for obtaining icons by file name alone:

extension UIImage {
	public class func icon(forFileNamed fileName: String, preferredSize: FileIconSize = .smallest) -> UIImage {
		return icon(forFileURL: URL(fileURLWithPath: fileName), preferredSize: preferredSize)
	}
}

Here we use it to get the icon for an arbitrary Pages file which may or may not exist:

Screenshot of calling the code snippet above to obtain a file icon for a Pages document.

Ah, now this is starting to feel even cooler than AppKit. But wait, NSWorkspace also supports another handy method:

let zipIcon = NSWorkspace.shared.icon(forFileType: "zip")

Well, we can achieve similar by taking advantage of the icon(forFileNamed:) method:

extension UIImage {
	public class func icon(forPathExtension pathExtension: String, preferredSize: FileIconSize = .smallest) -> UIImage {
		let baseName = "Generic"
		let fileName = (baseName as NSString).appendingPathExtension(pathExtension) ?? baseName
		return icon(forFileNamed: fileName, preferredSize: preferredSize)
	}
}

Now we’re really catching up:

Screenshot of code calling the iconForPathExtension example above.

But AppKit’s equivalent actually works on UTI type strings, as well. Wouldn’t that be cool to support on iOS? Seeing as MobileCoreServices gives us access to low level functions for converting UTI and file extensions, we can take a UTI, convert it, and let our existing helper methods take it from there:

import MobileCoreServices

extension FileManager {
	public func fileExtension(forUTI utiString: String) -> String? {
		guard
			let cfFileExtension = UTTypeCopyPreferredTagWithClass(utiString as CFString, kUTTagClassFilenameExtension)?.takeRetainedValue() else
		{
			return nil
		}

		return cfFileExtension as String
	}
}

extension UIImage {
	public class func icon(forUTI utiString: String, preferredSize: FileIconSize = .smallest) -> UIImage? {
		guard let fileExtension = FileManager.default.fileExtension(forUTI: utiString) else {
			return nil
		}
		return icon(forPathExtension: fileExtension, preferredSize: preferredSize)
	}
}

And voila!

Screenshot of code calling the iconForUTI code above.

It would be fairly easy to further extend this to support creating icon images from MIME types. Hope this helps some of you folks, especially coming from the Mac, who expected getting icons for file types to be slightly easier than it is.

Getting a CFNumber’s Value in Swift

Recently, as a consequence of working with the CGImageSource API, I found myself in a situation where I had hold of a CFNumber and wanted to get its value, as a CGFloat, in Swift.

CFNumber wraps numeric values in such a way that, to get the value out, you have to specify both the desired type, and provide a pointer to the memory of the variable that will hold the value. This kind of direct memory manipulation is not particularly suited to Swift’s priorities for type safety and memory protection. Here’s the API I’d need to use in Swift:

func CFNumberGetValue(_ number: CFNumber!, 
                    _ theType: CFNumberType, 
                    _ valuePtr: UnsafeMutableRawPointer!) -> Bool

The first two parameters are straightforward, but whenever I see types like “UnsafeMutableRawPointer” in Swift, my brain melts down a little. I have never really sat down to truly understand the nuanced differences between these types, so I usually just try something and hope it works. Here I am hoping for a gift from Swift’s implicit bridging:

// myCFNumber is 30.5
var myFloat: CGFloat = 0
CFNumberGetValue(myCFNumber, .floatType, &myFloat)
print(myFloat) // "5.46688490824244e-315\n"

Welp. That didn’t work. Let’s see if we can refresh our memory about UnsafeMutableRawPointer. In the section titled “Raw, Unitialized Memory” or I read:

You can use methods like initializeMemory(as:from:) and moveInitializeMemory(as:from:count:) to bind raw memory to a type and initialize it with a value or series of values.

Oh jeez, am I really going to have to manually create an UnsafeMutableRawPointer? I’ll try anything:

var myFloat: CGFloat = 0
var myFloatPointer = UnsafeMutableRawPointer(mutating: &myFloat)
CFNumberGetValue(myCFNumber, .floatType, myFloatPointer)
print(myFloat) // "5.46688490824244e-315\n"

Alas, same problem. Surely somebody has figured this out? I try Googling for “CFNumberGetValue Swift GitHub” and find a promising result from an authoritative source. The Swift standard library itself!

var value: Float = 0
CFNumberGetValue(_cfObject, kCFNumberFloatType, &value)

Aha! Practically the same thing I was doing, except for one nuanced detail: the var value is declared as a Float instead of a CGFloat. But wait a minute, what file is this implementation in? NSNumber.swift? Oh, right. NSNumber and CFNumber are toll-free bridged, and Swift’s standard library fulfills that promise too:

let myFloat = (myCFNumber as NSNumber).floatValue
print(myFloat) // 30.5

In fact, Swift’s Float type is even cozier with CFNumber than I expected. What started as a confused mission to make use of CFNumberGetValue and its unsafe pointer argument culminated in a bit of sample code from GitHub that ultimately led me to the understanding that the way to get a CFNumber’s value in Swift is … simply to ask for it:

let myFloat = Float(myCFNumber)
print(myFloat) // 30.5

Optional Emptiness

Objective-C developers are comfortable with many idioms that fall out of the safety of messaging nil. For example, consider a chunk of Objective-C code that tests the “emptiness” of a UITextField string:

if (myTextField.text.length == 0) {
    // Do something
}

If myTextField.text is nil, what happens? In Objective-C, a message sent to nil will return nil, or zero, depending on the return type of the message. In this case “length” returns an integer, which happens to be zero when text is an empty string, and zero when text is nil. So this code block perfectly expresses “if the text is empty, do something.”

Adapting this code to Swift, you immediately run up against the language’s strict handling of optionals. Because myTextField.text might be nil, it has to be unwrapped before the length method can be called. This leads to less terse code such as:

if myTextField.text?.isEmpty != false {
    // Do something
}

This works! But it’s harder to read, and harder to reason. Similarly to the way the Objective-C version requires deep understanding of that language’s nil-messaging behavior, the Swift version requires deep understanding of optional chaining and comparison of optional and non-optional values. Here’s another example:

if (myTextField.text ?? "").isEmpty {
    // Do something
}

This is much easier to understand: use the non-nil String from myTextField, or else a constant string that is guaranteed to return true for isEmpty. It’s still more cumbersome than the original Objective-C, though.

In my own Swift adventures, I’ve addressed this using Swift’s powerful extension mechanism. It turns out that in Swift, any type that conforms to the “Collection” protocol implements an “isEmpty” method. String is one of these types. So with a small extension, we can add the “isEmpty” method not only to String? but to all optionals that wrap a collection:

extension Optional where Wrapped: Collection {
	public var isEmpty: Bool {
		switch(self) {
		case .none:
			return true
		case .some(let concreteSelf):
			return concreteSelf.isEmpty
		}
	}
}

With this extension in place, our test becomes:

if myTextField.text.isEmpty {
    // Do something
}

Which is both highly readable, behaves correctly when “text” is nil, and doesn’t require any deep language understanding to comprehend.

Thanks to Hwee-Boon Yar for the Objective-C scenario that motivated this post, and to Michel Fortin for putting forward the Swift equivalents cited above. This question came up in the Core Intuition Slack, where interesting discussions like this often take place. Join us!

Playground Graphs

I was playing around with the Swift standard library’s “map” function, when I noticed a cool feature of Xcode Playgrounds. Suppose you are working with an array of numbers. In the Xcode Playgrounds “results” section, you can either click the Quick Look “eye” icon, or click the little results rectangle to get an inline results view of the expression you’re viewing:

Screenshot of Xcode Playgrounds's inline results view, revealing the values of an array of numb ers.

The linear list of values is revelatory and easy to read, but wouldn’t it be easier to understand as a graph? It turns out simply passing these values through the map function does just that:

Screenshot of the Xcode Playgrounds's result of the map function when returning numeric values.

I thought I had stumbled on some magical secret of Xcode, but it turns out the behavior is well documented, and applies to more than just the “map” function. You can even grab the edges of the result view and resize it to better suit your data. In fact, any looping numeric value seems to trigger the availability of this handy graphing functionality:

Screenshot of Xcode Playgrounds showing a graph of the results of Fibonacci sequence.

I am still frustrated by a lot of behaviors of Xcode Playgrounds, but little gems like these are nice to stumble upon.

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.

Principally Unclassy

I had a real head-scratcher of a bug with MarsEdit, manifesting as a subtle failure of specific AppleScript commands to work properly in the release builds of the app. It seemed as though AppleScript were unable to reckon any properties of my app stemming directly from the application object itself.

I was so perplexed that I found myself digging around inside AppleScript’s own internal handling of the command. Setting a breakpoint on -[NSScriptCommand executeCommand], I could trace the evaluation of the request from AppleScript, watching as it ultimately failed to handle the command and returned an error.

It made sense to discover that, in the course of determining how to handle the command, it would consult the application’s “top level object.” That is, the application object itself. I witnessed that AppleScript internally determines the object by calling something like this:

(lldb) po [[NSScriptExecutionContext sharedScriptExecutionContext] topLevelObject]
<NSApplication: 0x618000160600>

Well, that all looks pretty ordinary. Nothing to be alarmed by, right? Luckily, it jumped out at me as all wrong, even though it’s the subtlest of things. The instance returned above is of class NSApplication, which would normally be fine, except that I’ve subclassed NSApplication in my app. It should be of class MEApplication.

Apple doesn’t encourage subclassing NSApplication, but it’s well-documented and appropriate in some circumstances. I happen to implement some of MarsEdit’s high level scripting support in the NSApplication subclass.

I double-checked the target’s Info.plist file. Sure enough the value for NSPrincipalClass is “MEApplication”, so why am I getting an NSApplication instance instead? And why did this suddenly start happening in recent beta test releases of the app?

The answer is that I added an innocuous looking call to -[NSApplication sharedApplication] in MarsEdit’s main.m, before the call to NSApplicationMain. And this code path doesn’t get reached on Debug builds, only on Release ones. Sigh.

It’s in NSApplicationMain that the documented behavior occurs of looking up NSPrincipalClass from the Info.plist, and using that value to call -[WhateverClass sharedApplication]. By calling -[NSApplication sharedApplication] before that, I preemptively force the shared application instance to be of class NSApplication.

So remember, kids: don’t subclass NSApplication. But if you do, then don’t reference -sharedApplication before NSApplicationMain. And if you simply must, then make darned sure you explicitly target your custom subclass by name. For you iOS developers, this wisdom applies to UIApplication, as well!

Nasty. Yeah.