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 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
.
According to the Swift-eBook, which states the following
„Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.“
I would answer to your first two questions with Yes.
Do I need to include an if let block when examining it...
No, this is not necessary.
来源:https://stackoverflow.com/questions/24061039/how-is-a-return-value-of-anyobject-different-from-anyobject