I am new to swift and Maps. I am facing problem with displaying user live location. I have to display user location like Uber and Ola. I am getting array of coordinates from server.
This is the way i am fetching coordinates from server. I want to show moving user location. see following my code.
func SetUpMapsUI()
{
AdminAPIManager.sharedInstance.getAdminRunningStatusFromURL(){(resignationsJson)-> Void in
let swiftyJsonVar = JSON(resignationsJson)
let status = swiftyJsonVar["status"].rawString() as! String
print("status",status)
let message = swiftyJsonVar["message"].rawString()
if status.isEqual("0"){
if (message?.isEqual("No trips done so far."))!
{
self.mapViewBottomCons.constant = 0
}else
{
self.mapViewBottomCons.constant = 70
}
self.Bottom_view.isHidden = true
Toast.short(message: message as! String)
return
}
let busVar = swiftyJsonVar["bus_details"].rawString()!
let jsonData = busVar.data(using: .utf8)!
let LocationArray = try? JSONSerialization.jsonObject(with: jsonData, options: []) as! Array< Any>
for data in LocationArray!
{
let dic = data as! NSDictionary
guard let lat = dic.value(forKey: "latitude") as? Double else {
return
}
print("latlatlatlat",lat)
guard let lon = dic.value(forKey: "longitude") as? Double else {
return
}
print("longitude",lon)
self.arrayMapPath.append(NewMapPath(lat: Double(lat), lon: Double(lon)))
}
if self.arrayMapPath.count > 0
{
self.drawPathOnMap()
}
}
here is library that does that functionality it is written for both swift and ObjC..
ARCarMovement
here is a Stackoverflow SO answer
Related
I am using the code below to retrieve data from MySQL to show multiple locations on MKMapView using Swift.
The data and locations shows on the map, but what I could not figure out is how to adjust the zoom to cover all locations in that area.
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do {
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let evIdL = jsonElement["id"] as? String,
let evUserNameL = jsonElement["username"] as? String,
let evNotikindL = jsonElement["notikind"] as? String,
let evLatiL = jsonElement["lati"] as? String,
let evLongiL = jsonElement["longi"] as? String,
let evLocatL = jsonElement["locat"] as? String,
let evTimedateL = jsonElement["timedate"] as? String,
let evDistanceL = jsonElement["distance"] as? String
{
location.evId = evIdL
location.evUsername = evUserNameL
location.evNotikind = evNotikindL
location.evLati = evLatiL
location.evLongi = evLongiL
location.evLocat = evDistanceL
location.evTimedate = evTimedateL
location.evDisatnce = evDistanceL
location.evLocat = evLocatL
// the code to show locations
let latiCon = (location.evLati as NSString).doubleValue
let longiCon = (location.evLongi as NSString).doubleValue
let annotations = locations.map { location -> MKAnnotation in
let annotation = MKPointAnnotation()
annotation.title = evNotikindL
annotation.coordinate = CLLocationCoordinate2D(latitude:latiCon, longitude: longiCon)
return annotation
}
self.map.showAnnotations(annotations, animated: true)
self.map.addAnnotations(annotations)
}
locations.add(location)
}
DispatchQueue.main.async(execute: { () -> Void in
self.itemsDownloaded(items: locations)
})
}
I am using PHP file to connect with MySQL, as I said the code working and showing the locations but the zoom focus on one location only.
You can try
DispatchQueue.main.async {
self.map.addAnnotations(annotations)
self.map.showAnnotations(annotations, animated: true)
// make sure itemsDownloaded needs main ??
self.itemsDownloaded(items: locations)
}
I'm trying to build a route using Google Directions API. It returns an array of waypoints, however, the number of waypoints is not enough to build a smoothed route, and as the result I receive quite inaccurate route what is super crucial and inappropriate for transport application. I also tried HERE maps, almost the same result.
Is there any other services that may build more accurate route, or any solution applicable to the Google Directions API?
Here is the function:
public func getWaypoints(startLocation: [Double]!, endLocation: [Double]!, mode:String? = "walking", lang:String? = "en") -> [Dictionary<String,Any>] {
var resultedArray:[Dictionary<String,Any>] = []
let routeGM = Just.get("https://maps.googleapis.com/maps/api/directions/json?", params: ["origin":"\(startLocation[0]),\(startLocation[1])", "destination": "\(endLocation[0]),\(endLocation[1])", "mode": mode!, "key":self.KEY, "language": lang!])
if let _ = routeGM.error {
} else {
do {
if let data = jsonToNSData(routeGM.json! as AnyObject), let jsonData = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary {
let status = jsonData["status"] as! String
if(status == "OK") {
let results = jsonData["routes"] as! Array<Dictionary<String, AnyObject>>
let legs = results[0]["legs"] as! Array<Dictionary<String, AnyObject>>
let steps = legs[0]["steps"] as! Array<Dictionary<String, AnyObject>>
for i in 0...steps.count-1 {
let item = steps[i]
let start = item["start_location"] as! Dictionary<String,Any>
let end = item["end_location"] as! Dictionary<String,Any>
resultedArray.append(["start_location_lat": start["lat"]!,"start_location_lng": start["lng"]!,"end_location_lat": end["lat"]!,"end_location_lng": end["lng"]!])
}
}
else {
print("not found")
}
}
} catch {
print(error)
}
}
return resultedArray
}
Calling function:
func buildRoute(startCoord:[Double]!, endCoord:[Double]!) {
DispatchQueue.global(qos: .background).async {
let route:[Dictionary<String,Any>] = self.GMSRequest.getWaypoints(startLocation: startCoord,endLocation: endCoord, mode: "driving")
DispatchQueue.main.async {
let path = GMSMutablePath()
for item in route {
path.add(CLLocationCoordinate2D(latitude: item["start_location_lat"]! as! CLLocationDegrees, longitude: item["start_location_lng"]! as! CLLocationDegrees))
path.add(CLLocationCoordinate2D(latitude: item["end_location_lat"]! as! CLLocationDegrees, longitude: item["end_location_lng"]! as! CLLocationDegrees))
}
// Create the polyline, and assign it to the map.
self.polyline.path = path
self.polyline.strokeColor = Styles.colorWithHexString("#3768CD")
self.polyline.strokeWidth = 3.0
self.polyline.geodesic = true
self.polyline.map = self.mapView
}
}
}
Here,
i have source latitude & longitude
in the same way i also have destination latitude & longitude
Now, i want to show the path between these two lat & long's
sourcelatitude = 12.9077869892472
sourcelongitude = 77.5870421156287
print(sourcelatitude!)
print(sourcelongitude!)
destinationlatitude = 12.907809
destinationlongitude = 77.587066
print(destinationlatitude!)
print(destinationlongitude!)
Could any one help me with this
Try this
let origin = "\(12.9077869892472),\(77.5870421156287)"
let destination = "\(12.907809),\(77.587066)"
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)")
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!)
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .blue
polyline.strokeWidth = 4.0
polyline.map = mapViewX//Your GMSMapview
}
})
}
}catch let error as NSError{
print(error)
}
}
}).resume()
var aPosition = "30.9621,40.7816"
let bPosition = "26.9621,75.7816"
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(aPosition)&destination=\(bPosition)&key=\(your google key)"
//let urlString = "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=\(aPosition)&destinations=\(bPosition)&key=AIzaSyCaSIYkkv41RTn5vFLiSoZFlCUhIg-Db5c"
print(urlString)
Alamofire.request(urlString)
.responseJSON { response in
if let array = json["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)
self.polyline.path = path
self.polyline.strokeWidth = 4
self.polyline.strokeColor = UIColor.blue
self.polyline.map = self.mapView
}
}
}
}
}
I seem to have picked up a few errors since updating to swift 3
// Issue #1
let correctedAddress:String! = self.searchResults![(indexPath as NSIndexPath).row].addingPercentEncoding(withAllowedCharacters: CharacterSet.symbols)
print(correctedAddress)
let url = URL(string: "https://maps.googleapis.com/maps/api/geocode/json?address=\(correctedAddress)&sensor=false")
let task = URLSession.shared.dataTask(with: url!) {
data, response, error in
do {
if data != nil{
let dic = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
// Issue #2
let results = dic["results"] as! [String: Any]
let geometry = results["geometry"] as! [String: Any]
let location = geometry["location"] as! [String: Any]
let lat = location["lat"] as! Double
let lon = location["lng"] as! Double
self.delegate.locateWithLongitude(lon, andLatitude: lat)
}
}
catch {
print("Error")
}
}
task.resume()
issue #1:
correctedAddress, as an example, returns value "%51%75%C3%A9%62%65%63%2C%20%43%61%6E%61%64%61". Nevertheless, for some reason the url constant returns nil and causes a crash.
I don't understand why it returns nil. I can replace correctedAddress inside the url with the value %51%75%C3%A9%62%65%63%2C%20%43%61%6E%61%64%61 so the full url is
let url = NSURL(string: "https://maps.googleapis.com/maps/api/geocode/json?address=%51%75%C3%A9%62%65%63%2C%20%43%61%6E%61%64%61&sensor=false") and it works fine.
issue #2:
It crashes just at let results to which i get back the error of Could not cast value of type '__NSArrayI' (0x108bb0c08) to 'NSDictionary' (0x108bb1108).
Try the below code for your Issue#2
let results = dic["results"] as! NSArray
for result in results {
let strObj = result as! NSDictionary
let geometry = strObj["geometry"] as! NSDictionary
let location = geometry["location"] as! NSDictionary
let lat = location["lat"] as! NSNumber
let lon = location["lng"] as! NSNumber
}
For issue#1, try the below code
let valueAtIndex = self.searchResults![(indexPath as NSIndexPath).row].addingPercentEncoding(withAllowedCharacters: CharacterSet.symbols)
guard let correctedAddress = valueAtIndex else { return }
let adrString:String = "https://maps.googleapis.com/maps/api/geocode/json?address=\(correctedAddress)&sensor=false"
let url:URL = URL(string: adrString)!
So I have a problem where I call save after putting some items in an object. I go to an API and I download some info and then I save it to another system for temporary use, however the .save() seems to only save 2 items, with no special pattern in which it selects. Can someone explain what the problem is?
let url = URL(string: link)
let spots = PFObject(className:"spot")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error)
}
else{
if let urlContent = data{
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers)
let results = (jsonResult as! NSDictionary)["results"]
let venueList = (results as! NSArray)
//print(jsonResult)
var i = 0
while i < venueList.count{
let venues = venueList[i] as! NSDictionary
let name = venues["name"] as! String
let geometry = venues["geometry"] as! NSDictionary
let location = geometry["location"] as! NSDictionary
let cLat = location["lat"] as! Double
let cLon = location["lng"] as! Double
let vPoint = PFGeoPoint(latitude: cLat, longitude: cLon)
//print(name," ", vPoint)
spots["venue"] = name
spots["name"] = vPoint
do{
try HotSpots.save()
print("Saved! ",name," ", vPoint)
}
catch{
print("Save Error")
}
i+=1
}
}
catch{
print("JSON Error")
}
}
}
}
task.resume()
}
The issue is that you're saving the two values always in the same PFObject instance.
Move the line let spots = PFObject(className:"spot") in the loop.
PS: Use Swift native types. For example this is more efficient
let location = geometry["location"] as! [String:Double]
let cLat = location["lat"]!
let cLon = location["lng"]!