3

In one of my apps I need to geocode address string. At first I considered using CLGeocoder. However, after I tried it I stumbled upon a problem which I described in this question.

The solution was to use Google's Geocoding APIs instead. I have now switched to them and managed to get them working by having the following functions:

func startConnection(){
    self.data = NSMutableData()
    let urlString = "https://maps.googleapis.com/maps/api/geocode/json?address=\(searchBar.text!)&key=MYKEY"
        
    let linkUrl:NSURL = NSURL(string:urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!)!
    let request: NSURLRequest = NSURLRequest(URL: linkUrl)
    let connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
        connection.start()
}
    
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
    self.data.appendData(data)
}
    
func connectionDidFinishLoading(connection: NSURLConnection!) {
    do {
        if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? [String: AnyObject] {
            print(json)
        }
    }
    catch {
        print("error1")
    }
}

This works great and resolves the problem which I had with CLGeocoder. However, in addition to extracting the coordinates of place, I need to also use Google's Timezone APIs to extract the timezone for each place.

Doing this with the NSURLConnection or NSURLSession seems to me a bit difficult as I would need to keep track of which session/connection returns. So, I would like to have some solution which uses completion handlers.

I have tried using Alamofire framework (using the correct branch for Swift 2.0). However, it seems like request() function is the wrong one to use in this case. I have tried:

let parameters = ["address":searchBar.text!,"key":"MYKEY"]
Alamofire.request(.GET, "https://maps.googleapis.com/maps/api/geocode/json", parameters: parameters).responseJSON(options:.AllowFragments) { _, _, JSON in
            print(JSON)
        }

And all I am getting printed is "SUCCESS". I hope that I am doing something wrong and it can be fixed because I would really like to be able to use closures instead of delegate calls.

My questions are:

  1. Is it possible to use Alamofire with Google Geocoding APIs?
  2. If so, can you please tell me what am I doing wrong?
  3. If it is not possible, can you please suggest me how to design a system with NSURSessions or NSURLConnections which would allow me to use completion handlers for each call instead of delegates?

P.S. I am aware that I can use synchronous requests but I would really like to avoid using that option

Update

It was suggested that adding .MutableContainers as an option should make responseJSON work. I tried the code below:

let apiKey = "MYKEY"
var parameters = ["key":apiKey,"components":"locality:\(searchBar.text!)"]
Alamofire.request(.GET, "https://maps.googleapis.com/maps/api/geocode/json", parameters: parameters).responseJSON(options:.MutableContainers) { one, two, JSON in
    print(JSON)
}

And all I get printed is "SUCCESS".

Community
  • 1
  • 1
Andriy Gordiychuk
  • 6,163
  • 1
  • 24
  • 59

1 Answers1

-1

Ok, I have finally figured this out (with the help from @cnoon). The value which is returned is of type Result. I couldn't find documentation for it, but the source code is available here.

In order to retrieve JSON below implementation can be used:

Alamofire.request(.GET, "https://mapss.googleapis.com/maps/api/geocode/json", parameters: parameters).responseJSON(options:.MutableContainers) { _, _, JSON in
    switch JSON {

    case .Failure(_, let error):
        self.error = error
        break

    case .Success(let value):
        print(value)
        break

    }
}

The value printed is the correct representation of response from Geocoding APIs.

Andriy Gordiychuk
  • 6,163
  • 1
  • 24
  • 59
  • 1
    This will certainly work with `responseJSON`. You just need to pass the custom reading options off to the serializer. It defaults to `.AllowFragments` and you apparently require `.MutableContainers `. – cnoon Aug 22 '15 at 18:18
  • @cnoon unfortunately it doesn't work. Please see the section "Update" in my question. Also, if you are able to, can you have a look at this question which I have about submitting for beta testing (the issue is definitely due to framework) http://stackoverflow.com/questions/32158112/alamofire-swift-2-cannot-submit-for-beta-testing-xcode-7-beta-5 – Andriy Gordiychuk Aug 23 '15 at 14:23
  • 1
    Success means it `IS` working. In the `swift-2.0` branch, `responseJSON` now returns a Result type which when printed, will print `SUCCESS` or `FAILURE`. If you need more info, then use `debugPrint`. Have a look at the `Result` type and the examples in the docs as to how to get the actual values out of the `Result`. – cnoon Aug 23 '15 at 16:28
  • @cnoon thank you for your comment. I couldn't find documentation for Result but I have looked at the code and figured out how to extract JSON from it. Will update my answer now. – Andriy Gordiychuk Aug 23 '15 at 19:21