Guard not unwrapping optional
try? JSONSerialization.jsonObject(with: data) as? [String:Any]
is interpreted as
try? (JSONSerialization.jsonObject(with: data) as? [String:Any])
which makes it a "double optional" of type [String:Any]??
.
The optional binding removes only one level, so that json
has
the type [String:Any]?
The problem is solved by setting parentheses:
guard let json = (try? JSONSerialization.jsonObject(with: data)) as? [String:Any] else {
break
}
And just for fun: Another (less obvious?, obfuscating?) solution is to
use pattern matching with a double optional pattern:
guard case let json?? = try? JSONSerialization.jsonObject(with: data) as? [String:Any] else {
break
}
Swift why unwrapping optional by guarding against NIL is not working
The type of s
is still Optional
, so whether you did a nil
check or not is irrelevant. The nil
check is done in runtime, while the type system is doing a compile-time check. The only way to ensure s
can never be nil
is via optional binding if let
or guard let
.
swift - unwrapping optional with guard let
It doesn’t make much sense to force unwrap the optional in a conditional let assingment. Remove the !
:
guard let articleTitle = self.articles?[indexPath.row]["title"].string else {return}
Otherwise the right-hand side will never produce nil but crash.
Not using unwrapping in guard statements
guard let unwrapped = optional
is an Optional Binding (no link available directly to the correct book section, unfortunately). It safely tries to unwrap the value in the optional. If there is a value, the unwrap succeeds, and the value is assigned to the given name.
You should heavily favor the use of optional bindings, with either guard
or if
(the difference is the scope of the "unwrapped" name) over the use of forced unwrapping with !
. A failed force unwrap is a fatal error; your program will simply crash.
Safely unwrapping optional with guard let in init()
Store the result as a property of your objects. Better yet, use a static property, not a global.
class iCloudManager {
static let defaultPath = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
let path: URL
init?() {
guard let path = iCloudManager.defaultPath else { return nil }
self.path = path
}
func function1() {
// uses self.path
}
func function2() {
// uses self.path
}
}
Unwrapping optionals to a pre-defined variable in the guard condition without creating a new constant
I would just test for nil
and then force unwrap when I know it's not:
var someString: String? = "hello"
let nonOptionalString: String // note, you don't have to initialize this with some bogus value
guard someString != nil else { return }
nonOptionalString = someString!
Or if someString
was a parameter to some method or closure, you can unwrap in the guard
statement using the same variable name, simplifying life even more:
func foo(someString: String?) {
guard let someString = someString else { return }
// now I can just use local `someString`, which is not optional anymore
}
If you're desperate to unwrap and exit-if-nil
in a single statement, you could theoretically write a function to unwrap if it can or throw an error if it can't:
extension Optional {
enum OptionalError: Error {
case unwrapFailed
}
func unwrap<T>() throws -> T {
if self == nil { throw OptionalError.unwrapFailed }
return self as! T
}
}
Then you can do:
do {
firstNonOptional = try firstOptional.unwrap()
secondNonOptional = try secondOptional.unwrap()
thirdNonOptional = try thirdOptional.unwrap()
} catch {
return
}
I think that's horrible overkill, but if you're desperate to distill it down to one line per unwrap, that's one way to do it.
Use guard with double-optional
You can use Guard as well as if let
if let getValue = something, let value = getValue {
print(value)
}
guard let getValue = something , let value = getValue else {
return
}
You can also use FlatMap
if let value = something.flatMap({ $0 }) {
print(value)
}
If you have any level of optionals e.g 3,4,5,7 you will get the value with Conditionally cast
let something: Bool????? = true
if let value = something as? Bool {
print(value) // prints true
}
Although use of guard let, not unwrapped error
You have to optional downcast all dictionaries to the proper type
guard let json = try NSJSONSerialization.JSONObjectWithData(tickerData, options: []) as? [String:AnyObject] else { return nil }
guard let tableauUn = json["result"] as? [String:AnyObject] else {return nil }
guard let tableauDeux = tableauUn["XXBTZEUR"] as? [String:AnyObject] else { return nil}
and the final value
let prix = tableauDeux["o"] as? String
using guard to check for nil without implicitly unwrapping
In your guard
code you would have to have a return statement in the else block. Like this...
guard json["error"] == nil else {
let error = json["error"]!
// handle error
return
}
// handle success
But you are correct. Having to force unwrap the error is not ideal.
So in this case. I think guard
is the wrong solution. Instead use if
but return from the conditional block. This removes the need for using an else block.
if let error = json["error"] {
print(error)
// handle error
return
}
// handle success...
// no need for else block. Just return from the if in the error case.
The difference between guard let
and if let
is where the unwrapped optional is scoped.
With guard it is scoped outside the block with if it is scoped inside the block.
After guard let url the value still needs to be unwrapped
urls
is actually of type [String: URL?]
. Note that the value type is optional, because URL.init(string:)
is failable.
When you try to get a value from this dictionary, you get a URL??
. The guard
only unwraps one layer of the optional.
One way to unwrap a nested optional (no matter how many layers), is to use as?
:
guard let url = urls["en"] as? URL else { return }
Related Topics
Swift Error: Failed to Get Module 'My_App' from Ast Context
Which Optimization Level Should I Choose for Release
Issue with Returning a Directory Enumerator from Nsfilemanager Using Enumeratoraturl in Swift
Swift Switch Case Compiler Error
How to Mutate an Array in a Dictionary
Filter on Calayer Except for a Shape Which Is an Union of (Non Necessarily Distinct) Rectangles
iOS 8 Sdk, Swift, Mapkit Drawing a Route
Access Id Does Not Work When Testing a Textfield with 'Issecuretextentry = True'
How to Add More Cases for Enum in Swift
Naming Convention for Private Properties
Realm: Predicate Returning Lazyfiltercollection - How to Convert to Results<T>
Swift 4 - Hmcharacteristictypeserialnumber Deprecated
Nscalendar in Swift - Init Can Return Nil, But Isn't Optional
Different UIfont Sizes for Different iOS Devices in Swift