Category Archives: ObjC

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.

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!

Better Swift Completion

Apple released Xcode 9 earlier this week, and in spite of a few glitches here and there, I have found the update to be an overall improvement over Xcode 8. It’s nice that Apple continues to invest in the core tools for Mac and iOS developers.

I’ve been dabbling in more and more Swift development lately, and it’s brought to light a shortcoming in Xcode’s code completion which has unfortunately not improved in Xcode 9: completion of Swift function calls when there is a large quantity of candidates.

Take for example NSAttributedString. If I want to initialize a new instance in Swift, I type “NSAttributedString(” to bring up the list of compatible init methods I can choose from:

SwiftCompletion

The problem at this point is that I have to navigate the menu by hand. I can’t narrow down the list of completions any further by typing, because the very next character I type will be interpreted as the manual filling out of parameters of the NSAttributedString initializer.

BadCompletion

This is a situation where Objective-C gets much nicer treatment in the editor. Because completion in Objective-C begins when I start typing “init”, and because the named first parameter is part of the init message name, I can winnow down the results quite a bit:

Pasted Image 9 22 17 11 24 AM

Better still, because Xcode performs a fuzzy match on the typing, I can proceed to type the names of additional parameters to zero in completely on the variation I want:

MEAppController AppDelegate m Edited

When I accept the completion, all of my typing is replaced with the expected, templated parameter placeholders for the chose initializer.

I filed Radar #34594940 requesting better completion for Swift.

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!