Swift: respondsToSelector?
Ah for those carefree days
Welcome to another glorious Swift post, brought to you from foggy outer sunset in San Francisco. I'm working full time on iOS and loving every minute of it.
Today, let's talk about optional method chaining and respondsToSelector
. Normally in Objective-C land, we have to do a little dance any time we want to handle selectors that may not be present or when working with an object of unknown type:
if([obj respondsToSelector:@selector(fizzyWizzle)]) {
[obj fizzyWizzle];
}
Swift has a nifty feature that allows us to skip the respondsToSelector:
dance and just make the method invocation optional. If the method doesn't exist, then pretend it returned nil or void. You may not believe it, but this is one case where Swift makes it easier to be dynamic.
1> import Foundation
2> var aNotification:NSNotification? = nil
aNotification: NSNotification? = nil
3> let frobulator = aNotification?.object?.fizzyWizzle?()
/var/.../repl12.swift:2:39: error: 'AnyObject' does not have a member named 'fizzyWizzle()'
let frobulator = aNotification?.object?.fizzyWizzle?()
^ ~~~~~~~~~~~
Houston, we have a problem. Why doesn't this work? NSNotification.object
is declared as AnyObject?
so what's the deal? It turns out that Swift requires the selector to be visibly defined on a protocol somewhere before it will accept the optional method invocation. (I believe this is actually a bug and not intended behavior so a future release should relax this requirement).
4> @objc protocol Selectorizer : NSObjectProtocol {
5. optional func fizzyWizzle()
6.}
7> let frobulator = aNotification?.object?.fizzyWizzle?()
frobulator = Optional(())
Notice that we don't have to make the object adopt the protocol, nor do a cast. The fact that the method is defined on an Objective-C protocol anywhere is good enough.
The other thing to note is Optional(())
. Swift often uses the empty tuple as a synonym for void
, so we effectively have an Optional<void>
. Not terribly useful, except we can determine if the method was successfully called or not. Combined with the null coalescing operator ??
we can construct a very terse chain of method calls that says "walk this chain of objects or methods on one object until you find something".
notification?.object?.fizzyWizzer?() ??
notification?.object?.fozzulator?() ??
notification?.object?.frumple?()
Next up: The Great Generics Effort-post.
This blog represents my own personal opinion and is not endorsed by my employer.