2

I am trying to do the following in swift - Trying to reverse decode a list of addresses in an array and print their latitude/longitude coordinates. The code I have is as follows.

    let addressArray = ["Address 1", "Address 2"]
    var coordinatesArray = [CLLocationCoordinate2D]()

    override func viewDidLoad() {
        super.viewDidLoad()
        createAddressList()
        printAddressList()
    }

    func printAddressList() {
        for i in 0 ..< addressArray.count  {
            print("Address = \(addressArray[i]) Coordinates = \(coordinatesArray[i].latitude),\(coordinatesArray[i].latitude)")
    }

    func createAddressList() {
        for i in 0 ..< addressArray.count {
            let address = addressArray[i]
            geocoder.geocodeAddressString(address, completionHandler: {(placemarks, error) -> Void in
                print("Address = \(address)");
                if let placemark = placemarks?.first {
                    let coordinate = placemark.location?.coordinate
                    self.coordinatesArray.append(coordinate!)
                }
            })
        }
    }
}

The code prints only the first address that's decoded and nothing happens then.

I do have a fix for this like the below one, which is to move the printAddressList call from viewDidLoad method like this

func createAddressList() {
    if count < self.addressArray.count {
        let address = addressArray[count]
        geocoder.geocodeAddressString(address, completionHandler: {(placemarks, error) -> Void in
            print("Address = \(address)");
            if let placemark = placemarks?.first {
                let coordinate = placemark.location?.coordinate
                self.coordinatesArray.append(coordinate!)
            }
            print("Count = \(self.count)")
            self.count += 1
            self.createAddressList()
        })
    } else {
        printAddressList()
    }
}

Even though the latter solution works, I see that it's not clean, would like to know the right way to do this while making the code readable and clean.

2 Answers 2

6

How about using this structure?

let workGroup = dispatch_group_create()

for i in 0..<addressArray.count {

    dispatch_group_enter(workGroup)

    performGeoCoding({  successCallback : 

            dispatch_group_leave(workGroup)

    })
}

dispatch_group_notify(workGroup, dispatch_get_main_queue()){ 
    successCallback()   
    printAddressList()                    
}

There is very nice tutorial about dispatch_group here.

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

4 Comments

First of all thanks for the suggestion. I understood more about dispatch groups from the link you gave. But I couldn't understand the solution you gave. My problem is that having the geocoding method inside the for loop. By the time the first address is decoded, the for loop has completed the second iteration. The question is why I am I not seeing the second address decoded at all (the print statement inside the geocode in my case). Should I be using a while loop instead of for loop.
I think it doesn't matter whether you use for loop or while loop. Like you mentioned in the title, it is asynchronous call which does not guarantee that the results of completion handler would return before printAddressList() gets called. For instance, by the time your first geocode request returns, your program already looped through address array and then might execute printAddressList function that will not print correct values. That is why I think you need to use dispatch_group so that you can wait until collecting all desired results from completion handler.
what is performGeoCoding and successCallback in this?
How would I store objects into another array and return that once every object is iterated in the addressArray?
2

A bit more updated would be something like:

let dispatchGroup = DispatchGroup()

for address in addressArray {
    dispatchGroup.enter()

    performGeoCoding { address in 
        dispatchGroup.leave()
    }
}

dispatchGroup.notify(queue: .main) {
    completionHandler()   
}

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.