Search code examples
iosgoogle-maps-api-3google-apiswift2alamofire

Alamofire with google geocoding api


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".


Solution

  • 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.