Passing a variable from a UIImagePickerController to other functions in Swift - swift

I have an issue I'm trying to figure out. I'm not sure what an "elegant" way to approach this would be. This is my first Swift project, so excuse me if I'm asking something ridiculous.
I have this controller/image picker to get me the latitude/longitude of a photo in a user's photo library.
//Get metadata from a photo. Save location (latitude/longitude)
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let picker = UIImagePickerController()
picker.delegate = self // delegate added
if let URL = info[UIImagePickerControllerReferenceURL] as? URL {
print("We got the URL as \(URL)")
let opts = PHFetchOptions()
opts.fetchLimit = 1
let assets = PHAsset.fetchAssets(withALAssetURLs: [URL], options: opts)
for assetIndex in 0..<assets.count {
var asset = assets[assetIndex]
var location = String(describing: asset.location!)
var photo_latitude = asset.location?.coordinate.latitude
var photo_longitude = asset.location?.coordinate.longitude
var coords : [String: Double] = ["longitude": photo_longitude!, "latitude": photo_latitude!]
PHAsset.fetchAssets(withALAssetURLs: [URL], options: nil)
dismiss(animated:true, completion: nil)
PHImageManager.default()
.requestImageData(for: asset,
options: nil) { resultData, response, orientation, info in
var data = resultData
DropboxClientsManager
.authorizedClient?
.files
.upload(path: "/development/image.jpg", mode: .overwrite, input : data!)
print(data!)
}
}
}
}
}
I'm also uploading the image they select to Dropbox.
Here's my issue. I want to get the address from the latitude and longitude, but I need some way to pass the latitude and longitude into the appropriate function. I'm using the following code with the Google Maps API to find an address from latitude and longitude.
let baseUrl = "http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true/false"
let apikey = "hiding_my_api_key"
func getAddressFromGoogle() {
Alamofire.request(baseUrl, method: .get).responseJSON {
response in
if response.result.isSuccess {
print("Successful request.")
var locationData = JSON(response.result.value!)
let streetAddress = locationData["results", 0, "formatted_address"]
print(streetAddress)
print(locationData)
}
else {
print("Error \(response.result.error)")
}
}
}
What would be the best way for me to pass photo_longitude and photo_latitude to my getAddressFromGoogle function?
Thanks in advance.

The typical Swift way to approach this would be to attack it head on. Latitude and longitude are both floating point numbers, and you would usually pass them as such:
func getAddressFrom(lat: Double, long: Double)
Once inside the getAddressFrom(_:_:) method, you would typically use an instance of number formatter to convert each Double to a String of the format Google’s API expects:
func getAddressFrom(lat: Double, long: Double) {
let baseUrl = "http://maps.googleapis.com/maps/api/geocode/json?", urlSuffix = "&sensor=true/false"
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 6
// Do other configuration to get the number formatter to produce the output you need…
let numberLat = NSNumber(floatLiteral: lat), numberLong = NSNumber(floatLiteral: long)
guard let textLat = numberFormatter.string(from: numberLat),
let textLong = numberFormatter.string(from: numberLong) else {
// Handle invalid latitude or longitude…
return
}
let completeUrl = baseUrl + textLat + "," + textLong + urlSuffix
// Remaining body of function…
}
In production, you would probably configure the number formatter in the class body to reuse for many images.
Looking at your image picker controller, I see the latitude and longitude you are pulling off the images are optional values, since they may or may not be nil. When calling getAddressFrom(_:_:), you would probably use optional binding to unwrap the optionals and handle the nil case:
guard let photo_latitude = photo_latitude, let photo_longitude = photo_longitude else {
// Handle a photo missing latitude, longitude, or both…
return
}
getAddressFrom(lat: photo_latitude, long: photo_longitude)
Note that it is uncommon to use underscores in variable names in Swift. photoLatitude and photoLongitude are more Swift-y.

Related

How can I get my MapView annotations to save when I leave the app?

func addPin(_ sender: UILongPressGestureRecognizer) {
let location = sender.location(in: self.mapView)
let locCoord = self.mapView.convert(location, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoord
annotation.title = titleTextField.text
self.mapView.addAnnotation(annotation)
print("This will become the annotation title: \(titleTextField.text).")
print(annotation.coordinate.latitude, annotation.coordinate.longitude)
}
I am new to swift and would like to know how to get my annotations to save after leaving the app. Also, how do I stop multiple annotations from forming if the user does not pick up their finger?
What you'll likely need to do is store the MKPointAnnotations as Data within UserDefaults. To do this, you'll create an array of dictionaries from all of the mapView's annotations:
func addPin(_ sender: UILongPressGestureRecognizer) {
let location = sender.location(in: self.mapView)
let locCoord = self.mapView.convert(location, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoord
annotation.title = titleTextField.text
self.mapView.addAnnotation(annotation)
//Create a dictionary from the annotation
let newAnnotationDict = [
"lat": locCoord.latitude
"lng": locCoord.longitude
"title": annotation.title
]
//Pull the stored annotations data
var annotationsArray: [[String:Any]]!
var annotationsData = UserDefaults.standard.data(forKey: "StoredAnnotations")
//If the data is nil, then set the new annotation as the only element in the array
if annotationsData == nil {
annotationsArray = [newAnnotationDict]
} else {
//If it isn't nil, then convert the data into an array of dicts
do {
//Convert this data into an array of dicts
annotationsArray = try JSONSerialization.jsonObject(with: annotationsData, options: []) as! [[String:Any]]
annotationsArray.append(newAnnotationDict)
} catch {
print(error.localizedDescription)
}
}
do {
//Use JSONSerialization to convert the annotationsArray into Data
let jsonData = try JSONSerialization.data(withJSONObject: annotationsArray, options: .prettyPrinted)
//Store this data in UserDefaults
UserDefaults.standard.set(jsonData, forKey: "StoredAnnotations")
} catch {
print(error.localizedDescription)
}
print("This will become the annotation title: \(titleTextField.text).")
print(annotation.coordinate.latitude, annotation.coordinate.longitude)
}
And then, when the view controller is opened again, you'll want to pull this Data from UserDefaults and parse it into an array of MKPointAnnotation objects.
class MapViewController: UIViewController {
//Whenever the view loads, check if there were any annotations stored last time
override func viewDidLoad() {
super.viewDidLoad()
//Check if the data for "StoredAnnotations" exists
if UserDefaults.standard.data(forKey: "StoredAnnotations") != nil {
var storedAnnotationObjects = [MKPointAnnotation]()
do {
//Get the data from UserDefaults
let storedAnnotationsData = UserDefaults.standard.data(forKey: "StoredAnnotations")!
//Convert this data into an array of dictionaries
let storedAnnotationsArray = try JSONSerialization.jsonObject(with: storedAnnotationsData, options: []) as! [[String:Any]]
for dict in storedAnnotationsArray {
//Initialize a new annotation and set the annotation's properties
let newAnnotation = MKPointAnnotation()
newAnnotation.coordinate = CLLocationCoordinate2D(latitude: dict["lat"] as! CGFloat, longitude: dict["lng"] as! CGFloat)
newAnnotation.title = dict["title"] as! String
newAnnotationObjects.append(newAnnotation)
}
//Add the annotation to the mapView
self.mapView.annotations = storedAnnotationObjects
} catch {
print(error.localizedDescription)
}
}
}
...
}
If annotations are being removed, you'll need to similarly convert the stored data into an array of dicts and remove the appropriate object and update the data.
There are many strategies for persistence on iOS and depend on many factors like how many annotations will you save, how sensitive is the data, etc.
Apple's persistence guide is here: https://developer.apple.com/library/archive/referencelibrary/GettingStarted/DevelopiOSAppsSwift/PersistData.html
You might be able to get away serializing the objects themselves though I don't really suggest this. Instead, consider writing your own annotation type that conforms to Codable to make persistence safer and easier. This tutorial does a reasonable job of covering your use case:
https://www.raywenderlich.com/5247-core-location-tutorial-for-ios-tracking-visited-locations#toc-anchor-022
It's annoying that CLLocationCoordinate2D is not Codable itself, which is why you have to jump through some hoops.

FlickrAPI trouble understanding

I have to make an app that has the user place a pin on a map and then pulls pictures from Flickr based off the pin's location. My professor gave us a FlickrAPI file to use but I am having trouble understanding what it is doing.
import Foundation
class FlickrAPI: NSObject {
static let sharedInstance = FlickrAPI() // Create a Singleton for the class
var photos: Array<String> = []
var errorLevel = 0
// Flickr Constants
let BASE_URL = "https://api.flickr.com/services/rest/"
let METHOD_NAME = "flickr.photos.search"
let API_KEY = "<API Key Here>"
func fetchPhotosFromFlickrBasedOn(Latitude lat: Double, Longitude lng: Double, PageToFetch pageToFetch: Int, completion: #escaping (_ error: Int, _ pg: Int, _ pgs: Int) -> Void) {
// Empty our Photos Array
photos.removeAll(keepingCapacity: true)
// Build Aurgument List
let methodArguments = [
"method": METHOD_NAME,
"api_key": API_KEY,
"lat": String(format: "%f", lat),
"lon": String(format: "%f", lng),
"accuracy": "15", // Accuracy (Street Level)
"radius": "1", // Distance
"radius_units": "km", // in Kilometers,
"safe_search": "1", // Safe (G Rated),
"content_type": "1", // Photos Only
"per_page": "100", // Photos per Page
"page": "\(pageToFetch)",
"extras": "url_m", // Return Photo URLs
"format": "json", // Request JSON data format
"nojsoncallback": "1" // No JSON Callback
]
// Initialize Shared Session
let session = URLSession.shared
let url = URL(string: BASE_URL + escapeUrlParameters(methodArguments))!
let request = URLRequest(url: url)
var page = 0
var pages = 0
// Setup Session Handler
let task = session.dataTask(with: request, completionHandler: {data, response, error in
self.errorLevel = 0 // Initialize Error Level
if error != nil {
self.errorLevel = 1 //***** Network Error
} else {
// Okay to Parse JSON
do {
let parsedResult: AnyObject = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as AnyObject
if let photosDictionary = parsedResult.value(forKey: "photos") as? NSDictionary {
if let photoArray = photosDictionary.value(forKey: "photo") as? [[String: AnyObject]] {
page = photosDictionary["page"] as! Int
pages = photosDictionary["pages"] as! Int
for photoDictionary in photoArray {
if let photoUrl = photoDictionary["url_m"] as? NSString {
let ext = photoUrl.pathExtension
let noExt = photoUrl.deletingPathExtension
let addThumbDesignation = (noExt + "_q_d") as NSString
let thumbUrl = addThumbDesignation.appendingPathExtension(ext)
self.photos.append(thumbUrl!)
} else {
NSLog("***** Could not obtain an Image URL at Index:%d for Owner:%#", self.photos.count, photoDictionary["owner"] as! String)
}
}
} else {
self.errorLevel = 4 //***** No "Photo" Array key present
}
} else {
self.errorLevel = 3 //***** No "Photos" Dictionary key present
}
} catch {
self.errorLevel = 2 //***** Parsing Error
}
completion(self.errorLevel, page, pages)
}
})
task.resume()
}
// Escape URL Parameters
func escapeUrlParameters(_ parms: [String : String]) -> String {
var urlParms = [String]()
for (key, value) in parms {
let escapedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
urlParms += [key + "=" + "\(escapedValue!)"]
}
return urlParms.isEmpty ? "" : "?" + urlParms.joined(separator: "&")
}
}
In my code I have this function:
#IBAction func addPin(_ gestureRecognizer: UILongPressGestureRecognizer) {
var touchPoint = gestureRecognizer.location(in: Map)
var newCoordinates = Map.convert(touchPoint, toCoordinateFrom: Map)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinates
Map.addAnnotation(annotation)
flickr.fetchPhotosFromFlickrBasedOn(Latitude: annotation.coordinate.latitude, Longitude: annotation.coordinate.longitude, PageToFetch: 1, completion: {error,pg,pgs in
print("Error: \(error)")
print("Page: \(pg)")
print("Pages: \(pgs)")
})
//flickr.escapeUrlParameters(<#T##parms: [String : String]##[String : String]#>)
}
I understand that the code should be sending json information that I am supposed to use to display the image results on my app but like I said I am having a hard time understanding my professor's code. My main problem is after calling the function it skips everything that needs to run to pull the photos. I am clearly missing what I need to have so that my code will execute what it needs.
The radius parameter you had in FlickrAPI specified a radius that was not valid for Flickr's API. It should be something lower than 50. You'll have to play around with to see what the max you can get away with is, if that's the route you want to go.
I would recommend using Postman to test URLs, rather than fiddling around debugging API issues in Xcode. Get your API call-oriented poop in a group before making calls in Xcode. It's a lot easier that way. In this case, just put a breakpoint at wherever the URL is, type po url in the debugger, copy the URL into Postman and see what comes back in Postman. API's like Flickr are pretty good at telling you what ****ed up. Also, don't be afraid to look at documentation for stuff. It makes life a lot easier. The documentation for this endpoint is located here.
When you get to the completion call, put another breakpoint and type po photos. It'll print out an array of strings, which are URLs for the photos.
You probably don't need the location manager or the usage description thing in your info.plist if you're just tapping on the map. Lastly, don't chuck an API key out there in an open forum like GitHub or SO.

Unable to get the data from a nested json swift

I'm learning swift.
I have a json from server.
[
{
"dId": 1,
"vendor": {
"vendorId": 1,
"name": "Gems",
"about": "Get Good quality stones",
"address": "JacksonVille Road",
"latitude": 12.232323,
"longitude": 77.230802,
},
"name": "Gems Delight",
}
]
I'm unable to parse this json and get the data from lat and lon and name from vendor.
My url method and my for loop how can I exactly get the latitude and longitude from the loop and put them on the map ?
My View did load method
override func viewDidLoad() {
super.viewDidLoad()
guard let gitUrl = URL(string: "localhost:8080/deals") else { return }
URLSession.shared.dataTask(with: gitUrl) { (data, response
, error) in
guard let data = data else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
var lat:Double
var lon:Double
var nam = ""
for items in json as! [AnyObject]{
// let te = type(of: items)
// print(te)
let new = items["vendor"]
for (it,key) in new as! [String:Any]{
// print(it,key)
// print(it["longitude"])
if it == "longitude"{
print(it,key)
lon = key as! Double
}
if it == "latitude"{
print(it,key)
lat = key as! Double
}
if it == "name"{
nam = key as! String
}
if (nam.isEmpty == false){
print("falsdalsdasldasd")
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
let camera = GMSCameraPosition.camera(withLatitude:lat, longitude:lon, zoom: 4.0)
let subView = GMSMapView.map(withFrame: self.view.bounds,camera:camera)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude:lat, longitude:lon)
marker.title = nam
// marker.snippet = "Australia"
marker.map = subView
self.mapView.addSubview(subView)
}
// print(it["longitude"])
}
// let te = type(of: items)
// for it in new as![AnyObject]{
//// print(it"])
// print(it)
//
// }
// print(items["vendor"].["latitude"])
// print(items.vendor)
// print(items[""])
// let nam = items["name"];
// let desc = items["description"];
// self.locationNames.append(nam as! String)
// self.locationDescription.append(desc as! String)
//
}
// self.colecVw.delegate = self
// self.colecVw.dataSource = self
// self.colecVw.reloadData()
// }
} catch let err {
print("Err", err)
}
}.resume()
print("coming here")
// Create a GMSCameraPosition that tells the map to display the
// coordinate -33.86,151.20 at zoom level 6.
// let mapView = GMSMapView(frame: CGRect(x: 0, y: 64, width: self.currentDeviceSize.width, height: self.bottomBgView.frame.minY - 64))
// view = mapView
//
// // Creates a marker in the center of the map.
// let marker = GMSMarker()
// marker.position = CLLocationCoordinate2D(latitude: -33.86, longitude: 151.20)
// marker.title = "Sydney"
// marker.snippet = "Australia"
// marker.map = mapView
}
Please help me as I'm learning to code my code might not be correct can please dont mind and load the data of lat and long onto the map. Should I construct an object and put them there ?
Variable 'lon' used before being initialized
Variable 'lat' used before being initialized
This is the error I get from the code.
The errors occur because lat and lon must have a value in the line
let camera = GMSCameraPosition.camera(withLatitude:lat, longitude:lon, zoom: 4.0)
which is not guaranteed if the key comparisons fail.
The condition is fulfilled if you write
var lat = 0.0 // The type Double is inferred
var lon = 0.0
But rather than enumerating the dictionary get the values for the keys directly and safely with optional binding
do {
// no mutableContainers !!
let json = try JSONSerialization.jsonObject(with: data) as! [[String:Any]]
for item in json {
if let vendor = item["vendor"] as? [String:Any],
let lat = vendor["latitude"] as? Double,
let lon = vendor["longitude"] as? Double,
let name = item["name"] as? String, !name.isEmpty {
print("falsdalsdasldasd")
// self.locationManager.delegate = self
// self.locationManager.requestWhenInUseAuthorization()
// self.locationManager.startUpdatingLocation()
let camera = GMSCameraPosition.camera(withLatitude:lat, longitude:lon, zoom: 4.0)
let subView = GMSMapView.map(withFrame: self.view.bounds,camera:camera)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude:lat, longitude:lon)
marker.title = name
marker.map = subView
self.mapView.addSubview(subView)
}
}
} catch {
print("Err", error)
}
And it's nonsensical to call the LocationManager methods in each iteration. Call them once at the beginning of viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
...
You can try
struct Root: Codable {
let dID: Int
let vendor: Vendor
let name: String
enum CodingKeys: String, CodingKey {
case dID = "dId"
case vendor, name
}
}
struct Vendor: Codable {
let vendorID: Int
let name, about, address: String
let latitude, longitude: Double
enum CodingKeys: String, CodingKey {
case vendorID = "vendorId"
case name, about, address, latitude, longitude
}
}
--
let arr = try? JSONDecoder().decode([Root].self, from:data)
print(arr?.forEach {$0.vendor.latitude })
See this one
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
Pass json to
if let data = json as? NSArray {
for data in data {
if let data = data as? [String: AnyObject] {
let dataID = data["dId"] as? Int
if let data = data[“vendor”] as? [String: AnyObject] {
let vendorID = data["vendorId"] as? Int
}
}
}
}

Swift Save images (screenshots) to nsuserdefaults

I have a program, where the user "creates" an image, and then the program takes a screenshot of the screen. I would then like to save this screenshot to a database, prefferebly nsuserdefaults, since I am accessing it later in a table view. Any other suggestions on how to approach this, are more than welcome :)
The code is like this
let screenshot = getScreenshot() // saves the screenshot
var imagePaths = [String]()
// get the array of previous screenshots
if let _ = NSUserDefaults.standardUserDefaults().objectForKey(theKey)
{
imagePaths = NSUserDefaults.standardDefaults().objectForKey(theKey) as! [String]
}
// then I want to get a path to the image something like
let imagePath = screenshot.getPath() // although this is not a valid method, this is basically what I want
// add the imagePath
imagePaths.append(imagePath)
// finally I save the image
NSUserDefaults.standardUserDefaults().setObject(imagePaths, forKey: theKey)
You can create directory in Documents and save there screenshots as usual files. Filename can be generated from date and time for uniqueness.
func saveImage(imageData: NSData)
{
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy hh.mm.ss"
let filename = "\(dateFormatter.stringFromDate(NSDate())).png"
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as! String
let imagesDirectory = documentsDirectory.stringByAppendingPathComponent("Images")
let filePath = imagesDirectory.stringByAppendingPathComponent(filename)
if !NSFileManager.defaultManager().fileExistsAtPath(imagesDirectory)
{
var error: NSError?
NSFileManager.defaultManager().createDirectoryAtPath(imagesDirectory, withIntermediateDirectories: false, attributes: nil, error: &error)
if error != nil
{
println("\(error!.localizedDescription)")
return
}
}
imageData.writeToFile(filePath, atomically: true)
}
func getImagesPaths() -> [String]?
{
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as! String
let imagesDirectory = documentsDirectory.stringByAppendingPathComponent("Images")
if let filenames = NSFileManager.defaultManager().contentsOfDirectoryAtPath(imagesDirectory, error: nil)
{
let imagePaths = filenames.map{"\(imagesDirectory)/\($0)"}.filter(){$0.pathExtension == "png"}
return imagePaths.count > 0 ? imagePaths : nil
}
return nil
}
To save image simply use saveImage(data). To get images paths use getImagesPaths().
If you need array of UIImage, you can get it by follow way:
var images : [UIImage] = [ ]
if let imagePaths = getImagesPaths()
{
for path in imagePaths
{
if let image = UIImage(contentsOfFile: path)
{
images.append(image)
}
}
}

Swift iOS google Map, path to coordinate

I am trying to create a function in my app that will guide the user to a marker I have created.
This is the code I am using, it works great, It gets the users current location and show it on the map. But how can I get a directions to a marker?
Any awnser will be helpful
class Karta: UIViewController, CLLocationManagerDelegate {
#IBOutlet var mapView: GMSMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
//allow app to track user
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
//set out a marker on the map
var marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(56.675907, 12.858798)
marker.appearAnimation = kGMSMarkerAnimationPop
marker.icon = UIImage(named: "flag_icon")
marker.map = mapView
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Types Segue" {
let navigationController = segue.destinationViewController as UINavigationController
}
}
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
//If map is being used
if status == .AuthorizedWhenInUse {
var myLocation = mapView
locationManager.startUpdatingLocation()
mapView.myLocationEnabled = true
mapView.settings.myLocationButton = true
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if let location = locations.first as? CLLocation {
mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
locationManager.stopUpdatingLocation()
}
}
}
So i recently just solved this issue, here is my Swift 3 implementation using the latest version of Alamofire (4.3)
func fetchMapData() {
let directionURL = "https://maps.googleapis.com/maps/api/directions/json?" +
"origin=\(originAddressLat),\(originAddressLng)&destination=\(destinationAddressLat),\(destinationAddressLong)&" +
"key=YOUROWNSERVERKEY"
Alamofire.request(directionURL).responseJSON
{ response in
if let JSON = response.result.value {
let mapResponse: [String: AnyObject] = JSON as! [String : AnyObject]
let routesArray = (mapResponse["routes"] as? Array) ?? []
let routes = (routesArray.first as? Dictionary<String, AnyObject>) ?? [:]
let overviewPolyline = (routes["overview_polyline"] as? Dictionary<String,AnyObject>) ?? [:]
let polypoints = (overviewPolyline["points"] as? String) ?? ""
let line = polypoints
self.addPolyLine(encodedString: line)
}
}
}
func addPolyLine(encodedString: String) {
let path = GMSMutablePath(fromEncodedPath: encodedString)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5
polyline.strokeColor = .blue
polyline.map = whateverYourMapViewObjectIsCalled
}
Disclaimer:Swift 2
func addOverlayToMapView(){
let directionURL = "https://maps.googleapis.com/maps/api/directions/json?origin=\(srcLocation.coordinate.latitude),\(srcLocation.coordinate.longitude)&destination=\(destLocation.coordinate.latitude),\(destLocation.coordinate.longitude)&key=Your Server Key"
Alamofire.request(.GET, directionURL, parameters: nil).responseJSON { response in
switch response.result {
case .Success(let data):
let json = JSON(data)
print(json)
let errornum = json["error"]
if (errornum == true){
}else{
let routes = json["routes"].array
if routes != nil{
let overViewPolyLine = routes![0]["overview_polyline"]["points"].string
print(overViewPolyLine)
if overViewPolyLine != nil{
self.addPolyLineWithEncodedStringInMap(overViewPolyLine!)
}
}
}
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
}
Using the points, we now create the Path from two points using fromEncodedPath
func addPolyLineWithEncodedStringInMap(encodedString: String) {
let path = GMSMutablePath(fromEncodedPath: encodedString)
let polyLine = GMSPolyline(path: path)
polyLine.strokeWidth = 5
polyLine.strokeColor = UIColor.yellowColor()
polyLine.map = mapView
}
Unlike Apple's MapKit, the Google Maps SDK for iOS does not natively include a way to perform route calculations.
Instead, you need to use the Google Directions API: https://developers.google.com/maps/documentation/directions/. It is an HTTP-only API, and Google does not provide any SDK as of today, but you can easily write your own wrapper yourself, or choose one of the many options available on Github:
https://github.com/sudeepjaiswal/GoogleDirections
https://github.com/sebk/GoogleDirections
https://github.com/iamamused/iOS-DirectionKit
https://github.com/marciniwanicki/OCGoogleDirectionsAPI
and many others...
Its Very Simple
if you added a Google map SDK in your iOS Project and if you want to implement get google map direction lines between two different directions i have made as demo code in simple way understand using swift 2.3 try it, modify it and use it.!!!
Note: Dont Forgot to change your lat long you want and API Key (You may Use API key with None Restrictions on Google API Manager Credential Section)
func callWebService(){
let url = NSURL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(18.5235),\(73.7184)&destination=\(18.7603),\(73.8630)&key=AIzaSyDxSgGQX6jrn4iq6dyIWAKEOTneZ3Z8PtU")
let request = NSURLRequest(URL: url!)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
// notice that I can omit the types of data, response and error
do{
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {
//print(jsonResult)
let routes = jsonResult.valueForKey("routes")
//print(routes)
let overViewPolyLine = routes![0]["overview_polyline"]!!["points"] as! String
print(overViewPolyLine)
if overViewPolyLine != ""{
//Call on Main Thread
dispatch_async(dispatch_get_main_queue()) {
self.addPolyLineWithEncodedStringInMap(overViewPolyLine)
}
}
}
}
catch{
print("Somthing wrong")
}
});
// do whatever you need with the task e.g. run
task.resume()
}
func addPolyLineWithEncodedStringInMap(encodedString: String) {
let camera = GMSCameraPosition.cameraWithLatitude(18.5204, longitude: 73.8567, zoom: 10.0)
let mapView = GMSMapView.mapWithFrame(CGRect.zero, camera: camera)
mapView.myLocationEnabled = true
let path = GMSMutablePath(fromEncodedPath: encodedString)
let polyLine = GMSPolyline(path: path)
polyLine.strokeWidth = 5
polyLine.strokeColor = UIColor.yellowColor()
polyLine.map = mapView
let smarker = GMSMarker()
smarker.position = CLLocationCoordinate2D(latitude: 18.5235, longitude: 73.7184)
smarker.title = "Lavale"
smarker.snippet = "Maharshtra"
smarker.map = mapView
let dmarker = GMSMarker()
dmarker.position = CLLocationCoordinate2D(latitude: 18.7603, longitude: 73.8630)
dmarker.title = "Chakan"
dmarker.snippet = "Maharshtra"
dmarker.map = mapView
view = mapView
}