Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way of coping with Swift's nested "if let" "pyramid of doom?"

Is there a better way of dealing with a chain of optional properties than nested if let statements? I have been advised to use if lets when examining optional properties, which makes sense as it deals with them at compile time rather than run time, but it looks like utter madness! Is there is a better way?

Here is the current "pyramid of doom" I have ended up with, as an example:

( users: [ JSONValue ]? ) in

if let jsonValue: JSONValue = users?[ 0 ]
{
    if let json: Dictionary< String, JSONValue > = jsonValue.object
    {
        if let userIDValue: JSONValue = json[ "id" ]
        {
            let userID: String = String( Int( userIDValue.double! ) )
            println( userID )
        }
    }
}

Post-script

Airspeed Velocity's answer below is the right answer, but you will need Swift 1.2 to use multiple lets separated by commas as he suggests, which only currently runs in XCode 6.3, which is in beta.

like image 441
Joseph Beuys' Mum Avatar asked Mar 31 '15 09:03

Joseph Beuys' Mum


3 Answers

As commenters have said, Swift 1.2 now has multiple-let syntax:

if let jsonValue = users?.first,
       json = jsonValue.object,
       userIDValue = json[ "id" ],
       doubleID = userIDValue.double,
       userID = doubleID.map({ String(Int(doubleID))})
{
    println( userID )
}

That said, in this instance it looks like you could might be able to do it all via optional chaining in 1.1, depending on what your objects are:

if let userID = users?.first?.object?["id"]?.double.map({String(Int($0))}) {

    println(userID)

}

Note, much better to use first (if this is an array) rather than [0], to account for the possibility the array is empty. And map on the double rather than ! (which would blow up if the value is not double-able).

like image 176
Airspeed Velocity Avatar answered Nov 02 '22 08:11

Airspeed Velocity


UPDATE for Swift-3 : The syntax has changed :

if let jsonValue = users?.first,
       let json = jsonValue.object,
       let userIDValue = json[ "id" ],
       let doubleID = userIDValue.double,
       let userID = doubleID.map({ String(Int(doubleID))})
{
    println( userID )
}
like image 22
Sagar D Avatar answered Nov 02 '22 06:11

Sagar D


In Swift 2, we have the guard statement.

Instead of:

func myFunc(myOptional: Type?) {
  if let object = myOptional! {
    ...
  }
}

You can do it like this:

func myFunc(myOptional: Type?) {
  guard array.first else { return }
}

Check http://nshipster.com/guard-and-defer/ from NSHipster.

like image 22
gzfrancisco Avatar answered Nov 02 '22 06:11

gzfrancisco