In Swift, it's rare but possible to end up with a value of a non-optional type that has a nil value. As explained in answers to this question, this can be caused by bad Objective-C code bridged to Swift:
- (NSObject * _Nonnull)someObject {
return nil;
}
Or by bad Swift code:
class C {}
let x: C? = nil
let y: C = unsafeBitCast(x, to: C.self)
In practice, I've run into this with the MFMailComposeViewController
API in MessageUI
. The following creates a non-optional MFMailComposeViewController
, but if the user has not set up an email account in Mail, the following code crashes with EXC_BAD_ACCESS
:
let mailComposeViewController = MFMailComposeViewController()
print("\(mailComposeViewController)")
The debugger shows the value of mailComposeViewController
like this:
mailComposeViewController = (MFMailComposeViewController) 0x0000000000000000
I have a couple of questions here:
unsafeBitCast(_:to:)
says it "breaks the guarantees of the Swift type system," but is there a place in Swift documentation that explains that these guarantees can be broken, and how/when?mailComposeViewController == nil
since it's not optional.In Swift, if we define a variable to be an optional variable, in that case, this variable can have no value at all. If optional variable is assigned with nil , then this says that there is no value in this variable. To check if this variable is not nil, we can use Swift Inequality Operator != .
In Swift, nil means the absence of a value. Sending a message to nil results in a fatal error. An optional encapsulates this concept. An optional either has a value or it doesn't.
You can use if let. if let is a special structure in Swift that allows you to check if an Optional holds a value, and in case it does – do something with the unwrapped value. But for Strings you can also use . isEmpty() If you have initialized it to "" .
Unwrap an optional type with the nil coalescing operator If a nil value is found when an optional value is unwrapped, an additional default value is supplied which will be used instead. You can also write default values in terms of objects.
Even Apple's APIs sometimes return nil
for a type that is not marked in the API as Optional. The solution is to assign to an Optional.
For example, for a while traitCollectionDidChange
returned a UITraitCollection even though it could in fact be nil
. You couldn't check it for nil
because Swift won't let you check a non-Optional for nil
.
The workaround was to assign the returned value immediately to a UITraitCollection?
and check that for nil
. That sort of thing should work for whatever your use case is as well (though your mail example is not a use case, because you're doing it wrong from the get-go).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With