0

I have a loop that is taking taking elements of an array which is postcodes and changing them in a for loop into latitude, longitude, title and postcode and than creating and appending an array of dictionaries with the result. there is 3 postcodes in the original array and it shows this with a print but for some reason the loop isn't only looping 3 times it is doing it quite a few times this is giving me duplicate data, i have looked at removing the duplicates and this works in some way by leaving me with 3 results but sometimes the results are ok where the postcode and the title are all different but in some cases it comes back with the same title in with 2 different postcodes.

can anyone help with this point me in the right direction?

self.places = self.pCodes

// Loop start
for eachAddress in self.places {
                                let geocoder = CLGeocoder()
                                geocoder.geocodeAddressString(eachAddress) {
                                    placemarks, error in
                                    let placemark = placemarks?.first
                                    let lat = placemark?.location?.coordinate.latitude
                                    let lon = placemark?.location?.coordinate.longitude
                                    let postPcode = eachAddress
                                    let locationTitle = self.cNames[self.lt]
                                    let latLon = ["Post Code": postPcode, "title": locationTitle, "latitude":lat!, "longitude": lon!] as [String : Any]

                                    self.posts.append(latLon)

                                 // adding 1 to lt to pick the next title in the array

                                    if self.lt < (self.pCodes.count - 1) {
                                    self.lt += 1

                                    }else {
                                        self.lt = (self.pCodes.count - 1)
                            }


                                // removing duplicates
                                    var set = Set<String>()
                                    let arraySet: [[String : Any]] = self.posts.flatMap {
                                        guard let name = $0["Post Code"] as? String else {return nil }
                                        return set.insert(name).inserted ? $0 : nil
                                    }


                                    self.postsFinal = arraySet
                                    print("Tony Places \(self.places)")
                                    print("Tony: postsFinal \(self.postsFinal)")
                                    self.showSightingsOnMap()
                        }
                    }

and this is the print out I get.

Tony Places ["OL8 2TT", "PO1 5DS", "PO1 5JA"] Tony: postsFinal [["latitude": 53.514649900000002, "Post Code": "OL8 2TT", "title": "JDFG VBF", "longitude": -2.1052824000000001]] Tony Places ["OL8 2TT", "PO1 5DS", "PO1 5JA"] Tony: postsFinal [["latitude": 53.514649900000002, "Post Code": "OL8 2TT", "title": "JDFG VBF", "longitude": -2.1052824000000001]] Tony Places ["OL8 2TT", "PO1 5DS", "PO1 5JA"] Tony: postsFinal [["latitude": 53.514649900000002, "Post Code": "OL8 2TT", "title": "JDFG VBF", "longitude": -2.1052824000000001]] Tony Places ["OL8 2TT", "PO1 5DS", "PO1 5JA"] Tony: postsFinal [["latitude": 53.514649900000002, "Post Code": "OL8 2TT", "title": "JDFG VBF", "longitude": -2.1052824000000001], ["latitude": 50.800523599999998, "Post Code": "PO1 5DS", "title": "QWER QWE", "longitude": -1.0723248000000001]] Tony Places ["OL8 2TT", "PO1 5DS", "PO1 5JA"] Tony: postsFinal [["latitude": 53.514649900000002, "Post Code": "OL8 2TT", "title": "JDFG VBF", "longitude": -2.1052824000000001], ["latitude": 50.800523599999998, "Post Code": "PO1 5DS", "title": "QWER QWE", "longitude": -1.0723248000000001], ["latitude": 50.802415099999997, "Post Code": "PO1 5JA", "title": "QWER QWE", "longitude": -1.0726989]] Tony Places ["OL8 2TT", "PO1 5DS", "PO1 5JA"] Tony: postsFinal [["latitude": 53.514649900000002, "Post Code": "OL8 2TT", "title": "JDFG VBF", "longitude": -2.1052824000000001], ["latitude": 50.800523599999998, "Post Code": "PO1 5DS", "title": "QWER QWE", "longitude": -1.0723248000000001], ["latitude": 50.802415099999997, "Post Code": "PO1 5JA", "title": "QWER QWE", "longitude": -1.0726989]]

Tony Merritt
  • 1,177
  • 11
  • 35
  • Can you post the declaration for pCodes? Is it an NSArray, Array, etc. – Kris Gellci Aug 12 '17 at 19:11
  • @Kris Gellci var pCodes = [String]() pCodes is an array of postcodes exactly the same as places. I get the postcodes from Firebase database as a key and put them into an array. I also have var cNames = [String]() which is the value of the database and these are put into an array also. so I basically have 2 arrays 1 of the keys and the other of the values from firebase i then add these together with 2 other elements to create a dictionary. i then append the array of dictionaries into posts. – Tony Merritt Aug 12 '17 at 19:16
  • The way you are handling the async call is weird. I'd use a `dispatch_group()`instead: https://stackoverflow.com/questions/39465789/swift-how-to-use-dispatch-group-with-multiple-called-web-service – Larme Aug 12 '17 at 19:52
  • Ok thank you for the advice i will look at dispatching to get this working better for me. – Tony Merritt Aug 12 '17 at 20:38

1 Answers1

0

You have a few issues going on with this code. To get you started, the largest issue is geocodeAddressString. That is an async call and you are not guaranteed the order for which it is called. Are are handling indexing inside of the async call which is the reason that you are getting mismatched objects.

The code inside of the geocodeAddressString completion block is not executed in the order as you have coded it. Let's say you have 5 elements in the self.places array. For each one you make a call to geocodeAddressString.

geocodeAddressString(1)
geocodeAddressString(2)
geocodeAddressString(3)
geocodeAddressString(4)
geocodeAddressString(5)

The order in which geocodeAddressString executes the completion block could be something like this:

geocodeAddressString(2)
geocodeAddressString(5)
geocodeAddressString(1)
geocodeAddressString(3)
geocodeAddressString(4)

That is because geocodeAddressString is doing some work that takes an amount of time, possibly a network call. It will return as soon as it has the proper info which means that making 5 calls to it will have them all return at different rates. think of it like a race with 5 runners.

Kris Gellci
  • 9,539
  • 6
  • 40
  • 47