How is a return value of AnyObject! different from AnyObject

forced-unwrapping, swift

Solution

TLDR: Treat `Foo!` as if it were `Foo`.

Many Cocoa calls include implicitly unwrapped optionals, and their need for it is very likely the reason the feature even exists. Here's how I recommend thinking about it.

First, let's think about a simpler case that doesn't involve `AnyObject`. I think `UIDevice` makes a good example.

class func currentDevice() -> UIDevice!

What's going on here? Well, there is always a `currentDevice`. If this returned `nil` that would indicate some kind of deep error in the system. So if we were building this interface in Swift, this would likely just return `UIDevice` and be done with it. But we need to bridge to Objective-C, which returns `UIDevice*`. Now that should never be `nil`, but it syntactically could be `nil`. Now in ObjC, we typically ignore that fact and don't `nil`-check here (particularly because `nil`-messaging is typically safe).

So how would we express this situation in Swift? Well, technically it's an `Optional<UIDevice>`, and you'd wind up with:

class func currentDevice() -> UIDevice?

And you'd need to explicitly unwrap that every time you used it (ideally with an `if let` block). That would very quickly drive you insane, and for nothing. `currentDevice()` always returns a value. The `Optional` is an artifact of bridging to ObjC.

So they invented a hack to work around that (and I think it really is a hack; I can't imagine building this feature if ObjC weren't in the mix). That hack says, yes, it's an `Optional`, but you can pretend it's not, and we promise it's always going to be a value.

And that's `!`. For this kind of stuff, you basically ignore the `!` and pretend that it's handing you back a `UIDevice` and roll along. If they lied to you and return `nil`, well, that's going to crash. They shouldn't have lied to you.

This suggests a rule: don't use `!` unless you really need to (and you pretty much only need to when bridging to ObjC).

In your specific example, this works in both directions:

func valueForAttribute(key: String!) -> AnyObject!

Technically it takes an `Optional<String>`, but only because it's bridged to `NSString*`. You must pass non-`nil` here. And it technically returns you `Optional<AnyObject>`, but only because it's bridged to `id`. It promises that it won't be `nil`.

Problem

The `NSMetadataItem` class in the Cocoa framework under Swift contains the following function: `func valueForAttribute(key: String!) -> AnyObject!` I'm still learning the difference (and details) between forced unwrapping and optional chaining. In the above function, does this mean: The `key` parameter must have a value, and The return value is guaranteed to have a value? My primary concern is with the exclamation point following the return value - once I have assigned the return value: ``` var isDownloadedVal = item.valueForAttribute(NSMetadataUbiquitousItemIsDownloadedKey) ``` Do I need to include an `if let` block when examining it, or am I guaranteed that it will have a value I can examine safely?

Original source