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.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jan 19, 2015 at 1:10
\$\endgroup\$

1 Answer 1

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.

answered Jan 21, 2015 at 19:17
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.