0

I am struggling with a nice pattern about handling multiple optionals in my code and the corresponding error handling.

Hava a look at the following example

func getCoordinates1(pLatitude: Double?, pLongitude: Double?) -> CLLocationCoordinate2D?{
    var coord:CLLocationCoordinate2D?

    if let latitude = pLatitude {
        if let longitude = pLongitude {
            coord = CLLocationCoordinate2DMake(lat, long)
        }
    }

    return coord
}

This looks fine, but in a real world, you might need some error handling and here I am looking for a nice way of writing it down without duplicate code:

func getCoordinates2(pLatitude: Double?, pLongitude: Double?) -> CLLocationCoordinate2D? {
    var coord:CLLocationCoordinate2D?

    if let latitude = pLatitude {
        if let longitude = pLongitude {
            coord = CLLocationCoordinate2DMake(latitude, longitude)
        } else {
            // do something to catch the error
        }
    } else {
        // do the same as above (duplicate code)
    }

    return coord
}

What I sometimes do is that I use a boolean to keep track of it:

func getCoordinates3(pLatitude: Double?, pLongitude: Double?) -> CLLocationCoordinate2D? {
    var coord:CLLocationCoordinate2D?
    var success = false

    if let latitude = pLatitude {
        if let longitude = pLongitude {
            coord = CLLocationCoordinate2DMake(latitude, longitude)
            success = true
        }
    }
    if !success {
        // do something to catch the error
    }
    return coord
}

Or I use the pattern of exiting early, but I think this is also erroneous

func getCoordinates4(pLatitude: Double?, pLongitude: Double?) -> CLLocationCoordinate2D? {

    if let latitude = pLatitude {
        if let longitude = pLongitude {
            return CLLocationCoordinate2DMake(latitude, longitude)
        }
    }
    // do something to catch the error

    return nil
}

Of course this is a striped down example with only two optionals, but when parsing json, a lot more cascading-if might be necessary. I hope the idea and the problem is clear.

3
  • 1
    Is this what you are looking for stackoverflow.com/questions/24118900/… ? Commented Mar 20, 2015 at 8:51
  • Yes, but it will be available in Swift 1.2 (and currently this is beta only) Commented Mar 20, 2015 at 9:04
  • Just FYI, the pattern you're trying to avoid is called "The Pyramid Of Doom". Commented Mar 20, 2015 at 18:54

2 Answers 2

2

As mentioned in the comments, in Swift 1.2 you'll be able to do this:

func getCoordinates2(pLatitude: Double?, pLongitude: Double?) -> CLLocationCoordinate2D? {
    var coord:CLLocationCoordinate2D?

    if let latitude = pLatitude, longitude = pLongitude {
        coord = CLLocationCoordinate2DMake(latitude, longitude)
    } else {
        // do something to catch the error
    }

    return coord
}

I would suggest structuring your code to make it easier to switch to that style when it becomes available.

Try this:

func getCoordinates2(pLatitude: Double?, pLongitude: Double?) -> CLLocationCoordinate2D? {
    var coord:CLLocationCoordinate2D?

    if pLatitude != nil && pLongitude != nil {
        let latitude = pLatitude!
        let longitude = pLongitude!
        coord = CLLocationCoordinate2DMake(latitude, longitude)
    } else {
        // do something to catch the error
    }

    return coord
}

This has the same semantics and structure of the Swift 1.2 version, and when that becomes available, you can switch to the newer syntax without having to change any indentation.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your code. I kind of don't want to do that as I have the feeling that the idea of optionals is to avoid this kind of nil-testing. But I guess I just stick with the not-nil until 1.2
0

Essentially what you are trying to do can be split into two sets of operations:

  • First one is just plain processing of the data (payload)
  • And second is handling potential error-condition

Handling of error-condition is always the same, that is, check if previous operation returned an error and pass it upstream, and if so far everything was fine then process the result and pass success further on. This can be nicely encapsulated in a function that takes result and closure as an input and returns yet another result. I think this blog-post from Rob Napier will be quite useful for you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.