TIL About @nonobjc

In my free time, I run a Twitter account called Public Extension, where I share handy Swift extensions I’ve found or come up with. A recent extension involved adding custom subscripts to NSUserDefaults.

One attribute that sticks out is @nonobjc. Often times, you’ll need to use @objc1 to expose your Swift classes that don’t derive from an Objective-C class to the Objective-C runtime. It’s rare to explicitly cut that interoperability. Let’s dig into why this attribute is necessitated here by dropping it and deconstructing the compilation error:

The full error reads “Subscript getter with Objective-C selector ‘objectForKeyedSubscript:’ conflicts with previous declaration with the same Objective-C selector” (and the analog for the setter). Turns out that Objective-C also supports custom subscripting and Swift will automatically bridge them back! However, in our example, we’re overloading the subscript with the same key and different return types (also referred to as return type polymorphism), which Objective-C doesn’t support 😔. To fix this, we simply prevent the default bridging via @nonobjc.

So, there you have it! A real example of the @nonobjc attribute in action. Hope this post sheds some light on why it exists 😃

Shout-out to Joe Groff for the help and Garric Nahapetian for motivating me to write this post!

1: Swift also allows for the @objc(name) variant, which uses name when exposing the target class to the Objective-C runtime.