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, andThe 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?
TLDR: Treat
Foo!
as if it wereFoo
.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 thinkUIDevice
makes a good example.What's going on here? Well, there is always a
currentDevice
. If this returnednil
that would indicate some kind of deep error in the system. So if we were building this interface in Swift, this would likely just returnUIDevice
and be done with it. But we need to bridge to Objective-C, which returnsUIDevice*
. Now that should never benil
, but it syntactically could benil
. Now in ObjC, we typically ignore that fact and don'tnil
-check here (particularly becausenil
-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: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. TheOptional
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 aUIDevice
and roll along. If they lied to you and returnnil
, 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:
Technically it takes an
Optional<String>
, but only because it's bridged toNSString*
. You must pass non-nil
here. And it technically returns youOptional<AnyObject>
, but only because it's bridged toid
. It promises that it won't benil
.