5
\$\begingroup\$

I'm trying to parse an estimated travel duration and distance between two waypoints using Google Directions API. Tap on this to see an example of data received.

private class func parseTravelData(
    data: AnyObject!,
    mode: ESTMode,
    completion: (NSDictionary?) -> Void) {
        var receivedData = data as? NSDictionary

        if let routes = receivedData?["routes"] as? NSArray {
            if routes.count > 0 {
                if let legs = routes[0]["legs"] as? NSArray {
                    if legs.count > 0 {

                        var dur: String? = nil

                        if let duration = legs[0]["duration"] as? NSDictionary {
                            if let v = duration["value"] as? Float {
                                if v > ConnectionManager().timeMax && mode == .Walking {
                                    completion(nil) // resend using drive mode
                                }
                                else {
                                    if let t = duration["text"] as? String {
                                        dur = t
                                    }
                                }
                            }
                        }

                        if let d = dur {
                            if let distance = legs[0]["distance"] as? NSDictionary {
                                if let dist = distance["text"] as? String {
                                    completion([
                                        "duration": d,
                                        "distance": dist])
                                }
                            }
                        }
                    }
                }
            }
        }
}

This code works fine but looks awful. What I need is do nothing if data is incorrect. I can't come anything up with it. The main goal is avoiding of getting different unwrapping errors if something is wrong. I would greatly appreciate any help.

\$\endgroup\$
2
\$\begingroup\$

Not sure if this code is correct or will compile but here is my attempt...

private class func parseTravelData(data: AnyObject!, mode: ESTMode, completion: NSDictionary? -> Void) {
    let receivedData = data as? NSDictionary
    let routes = receivedData?["routes"] as? NSArray
    let legs = routes?.firstObject?["legs"] as? NSDictionary

    if let firstLeg = legs?.firstObject as? NSDictionary {
        let firstLegDurationDict = firstLeg["duration"] as? NSDictionary
        let firstLegDuration = firstLegDurationDict?["value"] as? Float

        if firstLegDuration > ConnectionManager().timeMax && mode == .Walking {
            completion(nil) // resend using drive mode
        } else if let durationStr = firstLegDurationDict?["text"] as? String {
            let distanceDict = firstLeg["distance"] as? NSDictionary
            if let distanceStr = distanceDict?["text"] as? String {
                completion(["duration": durationStr, "distance": distanceStr])
            }
        }
    }
}

Here are a few things I did to try to make the code more concise

I noticed that the interesting stuff only happens if the route contains a leg. So I was able to eliminate a few if statement blocks by using optional chaining and moving code out of the if conditions and into the receivedData, routes, and legs variables. (The individual variables are not strictly necessary but make the code more readable). So the first "if let" check happens to see if there is actually a leg in the optional legs array.

Another optimization I made is that I moved the if let d = dur block into the else statement above since the code will only proceed if duration["text"] exists. This also allowed me to eliminate the var dur: String? = nil statement as well.

I also renamed some variables for more clarity, for example I renamed v to firstLegDuration.

I was able to eliminate the if let v block since if v (which is now firstLegDuration) is nil then v > ConnectionManager().timeMax will be false since nil > AnyObject == false.

One thing I noticed that the completion does not get called in all cases, which to me seems weird, so if there is an error or missing data then nothing will happen.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.