Can't get directions from GoogleMaps because of "found nil" unrapping URL - swift

I searched through this topic and found some codes I tried to implement into my project, but it won't work!
So, what do I wanna achieve?
I wanna have a button in the UI, and when user tap the button, the app displays directions to a specific point on the GoogleMap. But my function crashes on the URL.
This is my code:
func draw(src: CLLocationCoordinate2D, dst: CLLocationCoordinate2D){
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(src)&destination=\(dst)&sensor=false&mode=driving&key=**API_KEY**" <- // Here I place API-Key
let url = URL(string: urlString) // Here is the crash!
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let routes = json["routes"] as! NSArray
self.mapView.clear()
OperationQueue.main.addOperation({
for route in routes
{
let routeOverviewPolyline:NSDictionary = (route as! NSDictionary).value(forKey: "overview_polyline") as! NSDictionary
let points = routeOverviewPolyline.object(forKey: "points")
let path = GMSPath.init(fromEncodedPath: points! as! String)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 3
let bounds = GMSCoordinateBounds(path: path!)
self.mapView!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 30.0))
polyline.map = self.mapView
}
})
}catch let error as NSError{
print("error:\(error)")
}
}
}).resume()
}
I don't know if the problem could be with the API-key, or if there's something else. I read that spaces etc could cause this issue, but I can't find what's wrong!
Error message:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
2019-06-14 16:50:45 Fatal error: Unexpectedly found nil while unwrapping an Optional value

You wrongly create urlString with directly using CLLocationCoordinate2D as you have to use it's properties latitude/longitude
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(src)&destination=\(dst)&sensor=false&mode=driving&key=**API_KEY**" <- // Here I place API-Key
it should be
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(src.latitude),\(src.longitude)&destination=\(dst.latitude),\(dst.longitude)&sensor=false&mode=driving&key=**API_KEY**" <- // Here I place API-Key
Also it's better to avoid ! and do
guard let url = URL(string: urlString) else { return }

Related

Fatal error: found nil - In calling Web API with JSON

Full error: Fatal error: Unexpectedly found nil while unwrapping an Optional value.
I am trying to get data from Web API service and am not sure where in the program it is getting nil value from.
Program crashes and getting error at line when declaring jsonResult
let urlAsString = "http://api.geonames.org/earthquakesJSON?north="+northString+"&south="+southString+"&east="+eastString+"&west="+westString+"&username=test"
let url = URL(string: urlAsString)!
let urlSession = URLSession.shared
let jsonQuery = urlSession.dataTask(with: url, completionHandler: { data, response, error -> Void in
if (error != nil) {
print(error!.localizedDescription)
}
var err: NSError?
let jsonResult = (try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)) as! NSDictionary //program crashes and gets error here
if (err != nil) {
print("JSON Error \(err!.localizedDescription)")
}
print(jsonResult)
let setOne:NSArray? = jsonResult["earthquakes"] as? NSArray
print(setOne?[0]);
let y = setOne?[0] as? [String: AnyObject]
let dateTime: String = (y!["datetime"] as? NSString)! as String
DispatchQueue.main.async{
self.date.text = String(dateTime)
}
})
jsonQuery.resume()
Seems like data is nil. You forcibly tried to set nil value.
if let data = data {
if let jsonResult = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as NSDictionary {
if let setOne = jsonResult["earthquakes"] as? [NSDictionary] {
let y = setOne[0] as? [String: AnyObject]
let dateTime: String = (y!["datetime"] as? String)! as String
DispatchQueue.main.async{
self.date.text = String(dateTime)
}
}
}
}
It crashes because you force unwrap a nil value. So try with optional instead
replace this line let jsonResult = (try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)) as! NSDictionary with:
do {
if let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)) as? NSDictionary {
// Rest of your code here
}
} catch let error {
}

how to get all possible routes using google map api

I would like to know all possible routes between two coordinate
, google map api gives me only one route, using this url: "https://maps.googleapis.com/maps/api/directions/json?origin=30.1124,31.4003&destination=29.9792,31.1342&provideRouteAlternatives=true&key=xx")
i can't find where are all the routes and to get them
here is the code
func getRoutes(handler:#escaping (_ error: String?) -> Void){
let request = URLRequest(url: URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=30.1124,31.4003&destination=29.9792,31.1342&provideRouteAlternatives=true&key=AIzaSyAf5emsTReEhPgC3NwAnXEdoa_CllLbyLc")!)
// request.addValue("provideRouteAlternatives", forHTTPHeaderField: "true")
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
if error != nil {
// Handle error...
handler("Connection Error")
return
}
let parsedResult: [String: AnyObject]!
do {
parsedResult = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: AnyObject]
print(parsedResult)
} catch {
print("Error parsing result as JSON")
handler("Cant download Student data")
return
}
if let array = parsedResult["routes"] as? NSArray {
if let routes = array[0] as? NSDictionary{
if let overview_polyline = routes["overview_polyline"] as? NSDictionary{
if let points = overview_polyline["points"] as? String{
print(points)
// Use DispatchQueue.main for main thread for handling UI
DispatchQueue.main.async {
// show polyline
let path = GMSPath(fromEncodedPath:points)
let polyline = GMSPolyline(path: path)
//self.polyline.path = path
polyline.strokeWidth = 4
polyline.map = self.myMap
}
}
}
}
}
handler(nil)
}
task.resume()
}
All the routes are present in the routes array in the JSON response.
In the case of particular origin and destination you specified, I see only one element in the routes array in the API response. But https://www.google.co.in/maps/dir/'30.1124,31.4003'/'29.9792,31.1342'/ shows multiple routes on the web version.
There is nothing you can probably do in your program to get all the routes unless Google provides it in the JSON response.

Thread 10: Fatal error: Unexpectedly found nil while unwrapping an Optional value

I am trying to make a service call to get user details however i get this error :
Thread 10: Fatal error: Unexpectedly found nil while unwrapping an Optional value
From this code :
let urlString = "http://myURL.com/getInfo/getAccountTransactions/{accountPublicKey}"
print(urlString)
let requestUrl = URL(string:urlString)
let requestURL = URLRequest(url:requestUrl!)
When i wrap the code in a guard let the code doesn't get executed because it finds nil, i am not sure why because the URL string can never be nill since its initialized with a default value on the same code.
This the code in a guard let :
let urlString = "http://myURL.com/getInfo/getAccountTransactions/{accountPublicKey}"
guard let requestUrl = URL(string:urlString) else { return }
let requestURL = URLRequest(url:requestUrl)
This the entire service call code :
class TransactionServiceCall : NSObject, URLSessionDelegate{
let viewResponse = ThrowResponse()
func fetchTransactions(requestObject: Transaction, completion: #escaping (Dictionary<String,Any>?) -> Void) {
let urlString = "http://myURL.com/getInfo/getAccountTransactions/{accountPublicKey}"
guard let requestUrl = URL(string:urlString) else { return }
let requestURL = URLRequest(url:requestUrl)
let searchParams = Transaction.init(publicKey: requestObject.publicKey)
var request = requestURL
request.httpMethod = "POST"
request.httpBody = try? searchParams.jsonData()
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
do {
let httpResponse = response as! HTTPURLResponse
let statusCode = httpResponse.statusCode
if 200 ... 299 ~= statusCode {
if let json = try JSONSerialization.jsonObject(with: data!) as? Dictionary<String,Any> {
self.viewResponse.dismissLoader()
print(json)
completion(json)
}
}else{
self.viewResponse.dismissLoader()
self.viewResponse.showFailureAlert(title: "Failure", message: "")
completion(nil)
}
} catch {
DispatchQueue.main.async {
self.viewResponse.dismissLoader()
self.viewResponse.showFailureAlert(title: "Failure", message: "")
completion(nil)
}
}
})
task.resume()
}
}
It is important to note that the url has curly brackets in it e.g
http://myURL.com/getInfo/getAccountTransactions/{accountPublicKey}
You need to escape special characters in the url string using addingPercentEncoding(withAllowedCharacters:) and an appropriate CharacterSet so that a valid URL object may be created from it.
In your case, the CharacterSet should be .urlQueryAllowed
Like so:
//The unescaped string
let unescaped = "http://myURL.com/getInfo/getAccountTransactions/{accountPublicKey}"
//The escaped string
let escaped = unescaped.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
//...

How to set google map zoom level according to path & markers in swift

I am trying to show path in google maps from one place to another place I am getting something like this. but I need to show like this. Which means the whole path need to show & according to path on map, the zooming level should adjust
Here is the code which I tried to draw path from API. and here in let settingCam am setting camera to adjust to one of the location
func showingPathFromPickupLocToDropLoc(dropLat: Double, dropLong: Double){
let origin = "\(dropLat),\(dropLong)"
let destination = "\(dropLatitude),\(dropLongitude)"
let settingCam: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: CLLocationDegrees(dropLat), longitude: CLLocationDegrees(dropLong))
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&key=\(NEWAPI.GOOGLE_APIKEY)")
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
if json["status"] as! String == "OK"{
let routes = json["routes"] as! [[String:AnyObject]]
OperationQueue.main.addOperation({
for route in routes{
let routeOverviewPolyline = route["overview_polyline"] as! [String:String]
let points = routeOverviewPolyline["points"]
let path = GMSPath.init(fromEncodedPath: points!)
self.PathFromPickupLocToDropLoc = GMSPolyline(path: path)
self.PathFromPickupLocToDropLoc.strokeColor = .gray
self.PathFromPickupLocToDropLoc.strokeWidth = 3.0
self.PathFromPickupLocToDropLoc.map = self.mapView
let camera = GMSCameraPosition.camera(withTarget: settingCam, zoom: 16.0)
self.mapView.animate(toLocation: settingCam)
self.mapView.animate(to: camera)
self.insertingMarkersFromPickupLocToDropLoc(dropLat: dropLat, dropLong: dropLong)
}
})
}
}catch let error as NSError{
print(error)
}
}
}).resume()
}
You need to do like this
DispatchQueue.main.async
{
if self.googleMap != nil
{
let bounds = GMSCoordinateBounds(path: path!)
self.googleMap!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}

how to check SwiftyJSON if returl nil in link

If my link does not return data how do I check in swiftyJSON,
I got this error : fatal error: unexpectedly found nil while unwrapping an Optional value
var URLString = mylink
URLString = URLString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let url = NSURL(string: URLString)!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, innerError) in
let jsonData = NSData(contentsOfURL: url)! as NSData? //>> here is the error fatal error: unexpectedly found nil while unwrapping an Optional value
let readableJson = JSON(data: jsonData!, options: NSJSONReadingOptions.MutableContainers, error: nil)
let jjson = readableJson[0]
let ID = jjson["Title"]
})
}
task.resume()
You should avoid the force unwrap "!".
Try this
func foo(urlAsString:String) {
guard let
urlAsStringEscaped = urlAsString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding),
url = NSURL(string: urlAsStringEscaped)
else { fatalError() }
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
if let data = data where error == nil {
let json = JSON(data: data)
let id = json[0]["Title"].string
}
}
task.resume()
}