Swift/GMaps - keep getting an error - ios

Please note - I have checked through SO for an answer to this. Many developers have answered, however I feel I have done what was needed.
I added the -ObjC to the project: Other Linker Flags.
I keep getting this error:
NSInvalidArgumentException', reason: '-[GMSMapView
animateToCameraPosition:]: unrecognized selector sent to instance
I have followed Googles steps - step by step as well as watching a number of videos (which are in ObjC) and reading a number of blogs.
I have added all frameworks and even unticked do not copy when adding the GMaps bundle.
Here is my code.
AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
Parse.enableLocalDatastore()
Parse.setApplicationId("ParseKey_eOHadu2GEOBqxvRl8ijKM0PMhq3", clientKey: "ParseKey_yFjq2MWocV3188hOq9MIjhqi5x0Od")
PFFacebookUtils.initializeFacebook()
GMSServices.provideAPIKey("MyKey_Pq9rjt5ZFX_jpB_QF5pEarMdp18_x4")
return true
}
Here is my viewController code
class UserLocationGm: UIViewController , GMSMapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
var camera = GMSCameraPosition.cameraWithLatitude(-33.86,
longitude: 151.20, zoom: 6)
var mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
mapView.myLocationEnabled = true
self.view = mapView
var marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(-33.86, 151.20)
marker.title = "Sydney"
marker.snippet = "Australia"
marker.map = mapView
}
Is something missing? i.e. I'm fairly sure that I am not meant to add a MapKit View to the viewController. Has anyone got any suggestions?
Xcode 6
Google Maps SDK: 1.9.1
Lang: Swift

Related

Sygic issue in showing the map

I have a problem with Sygic maps framework, I tried to show the map using this code
in the AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
SYContext.initWithAppKey("mhives.sdk.trial", appSecret: "2nxScQJ0s/J6FsYJ67dlQ+MZLjLzOKc0s96l0t4YyLv2IH8b31b5vWgkzbfgJZ8FYEKQtxpLFGlwyfqEQ64MSQ==") { (initResult) in
if (initResult == .success) {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController:ViewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
// Set that ViewController as the rootViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
initialViewController.sdkDidStart()
} else {
print("KO")
}
}
return true
}
the ViewController.swift
class ViewController: UIViewController,SYMapViewDelegate,SYRoutingDelegate {
let mapView = SYMapView()
let routing = SYRouting()
override func viewDidLoad() {
super.viewDidLoad()
}
func mapView(_ mapView: SYMapView, didFinishInitialization success: Bool) {
let tiltFor2D: SYAngle = 0
mapView.tilt = tiltFor2D
self.mapView.zoom = 10
self.mapView.rotation = 180
self.mapView.geoCenter = SYGeoCoordinate(latitude: 48.147, longitude: 17.101878)!
self.mapView.frame = self.view.bounds
view.addSubview(self.mapView)
}
func computeRoute(from fromCoordinate: SYGeoCoordinate, to toCoordinate: SYGeoCoordinate) {
// Create an instance of SYRouting
// Make self a delegate for SYRouting to receive and handle SYRoutingDelegate responses
// Create SYWaypoint from coordinate. Set correct SYWaypointType for start and finish.
let startWaypoint = SYWaypoint(position: fromCoordinate, type: .start, name: nil)
let endWaypoint = SYWaypoint(position: toCoordinate, type: .end, name: nil)
// Optionally: create an instance of SYRoutingOptions for configuring computing of a route
let routingOptions = SYRoutingOptions()
routingOptions.transportMode = .pedestrian // For other options see SYTransportMode
routingOptions.routingType = .economic// For other options see SYRoutingType
// Start computing route
self.routing.computeRoute(startWaypoint, to: endWaypoint, via: nil, with: routingOptions)
}
func routing(_ routing: SYRouting, computingFailedWithError error: SYRoutingError) {
print(error.rawValue)
}
func routing(_ routing: SYRouting, didComputePrimaryRoute route: SYRoute?) {
SYNavigation.shared().start(with: route)
// You might want to put it also on the map
let mapRoute = SYMapRoute(route: route!, type: .primary)
mapView.add(mapRoute)
}
Now I try to show simply the Sygic maps but I didn't get it and I receive this message in the debugger "Sygic: W 18/08/19 17:04:51 No SSO session, unable to send http request!"
func sdkDidStart(){
mapView.delegate = self
routing.delegate = self
self.mapView.frame = self.view.bounds
self.view.addSubview(self.mapView)
let start = SYGeoCoordinate(latitude: 37.276758, longitude: 9.864160900000002)
let end = SYGeoCoordinate(latitude: 37.25408, longitude: 9.906733)
//computeRoute(from: start!, to: end!)
}
Any help please
First of all do you have valid key and secret? If not you can request one here: https://www.sygic.com/business/request-sygic-mobile-sdk-api-key?product=mobileSdk
I understand you are not using real one here in example, but at least the error seems like the one you are using isn't valid.
The other thing is, when do you initialize your SYMapView? If you load ViewController as initial view controller using storyboard for example, then it will try to load map view instance and all of its underlying components before the SDK is fully loaded. Be careful, you should only work with SDK after it is successfully initialized.
So check your API keys and try to initialise that view controller in SYContext.initWithAppKey() completion handler.

Current location in not working in Google Map

I have integrated google map in swift 3, when map screen appear than current location in not showing, i have added two keys in .plist file and also set CLLocationManager delegate and requestAlwaysAuthorization
class MapViewController: UIViewController, CLLocationManagerDelegate, UITextFieldDelegate {
#IBOutlet var mapView: GMSMapView!
var marker: GMSMarker?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "MapVC"
self.doSetupUI()
self.searchLocation()
}
override func viewWillAppear(_ animated: Bool) {
let locationManager : CLLocationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
}
func doGoogleMapSetup(lat : Double , lng : Double) {
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude:lng, zoom:16)
let mapView = GMSMapView.map(withFrame: .zero, camera:camera)
mapView.isMyLocationEnabled = true
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
marker.snippet = ""
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
let arrPoints : NSMutableArray = NSMutableArray()
arrPoints.add(UserDefaults.standard.object(forKey: "addressPoints"))
for i in 0..<arrPoints.count {
let path : String = (arrPoints.object(at: i)as! NSMutableArray).object(at: 0) as! String
let route : GMSPath = GMSPath.init(fromEncodedPath: path)!
let polyLine : GMSPolyline = GMSPolyline.init(path: route)
polyLine.strokeWidth = 2.0
polyLine.strokeColor = UIColor.red
polyLine.map = mapView
}
}
For showing current location we don't need any location manager in case of GoogleMaps. All we need is to add one of the keys or both in the .plist. So make sure the key is there. I have used NSLocationWhenInUseUsageDescription key.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Allow location</string>
Also make sure that you have called GMSServices provideAPIKey method and replaced with the API_KEY you generated in google developer console. Also all the relevant Google APIs as per requirement should be enabled.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
GMSServices.provideAPIKey("YOUR_API_KEY")
return true
}
So, I am assuming you have done all the settings and things right in google developer console.
By just writing the below line in your controller where you have made the GoogleMap can show the location allow/disallow prompt and take the permission of the user.
mapView.isMyLocationEnabled = true
However this will not animate your map to your current location. But you can manually drag the map to check the current location and you will see a blue dot at your current location.
But now we also want to animate to the current location whenever we load that ViewController. Now the need for CLLocationManager arrives. So that in its didUpdateLocation delegate, we can fetch the current location and can just animate the graph to the current location.
So here is my complete controller.
import UIKit
import GoogleMaps
class ViewController: UIViewController,GMSMapViewDelegate,CLLocationManagerDelegate {
#IBOutlet weak var mapView: GMSMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.isMyLocationEnabled = true
mapView.delegate = self
//Location Manager code to fetch current location
self.locationManager.delegate = self
self.locationManager.startUpdatingLocation()
}
//Location Manager delegates
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let camera = GMSCameraPosition.camera(withLatitude: (location?.coordinate.latitude)!, longitude:(location?.coordinate.longitude)!, zoom:14)
mapView.animate(to: camera)
//Finally stop updating location otherwise it will come again and again in this delegate
self.locationManager.stopUpdatingLocation()
}
}
Another way of doing is not using the didUpdateLocation and not using the location manager is just by using the GMSMapViewDelegate delegate method mapViewDidFinishTileRendering
func mapViewDidFinishTileRendering(_ mapView: GMSMapView) {
let location = mapView.myLocation
let camera = GMSCameraPosition.camera(withLatitude: (location?.coordinate.latitude)!, longitude:(location?.coordinate.longitude)!, zoom:14)
mapView.animate(to: camera)
}
It will be called everytime the map rendering is finished.
But this comes with a limitation, it will always bring you to the current location whenever you drag/pinch/zoom map as the rendering finish everytime you play with map. So, you can just implement some kind of bool variable logic here.
You can get your location by using
let yourCurrentLocation = mapView.myLocation
Make sure to do this on a device rather than simulator. If you are using simulator, you have to choose some custom location and then only you will be able to see the blue dot.
I already gave this type of answer. Check this Link. But that was in Swift 2.x. The one which I posted in this answer is in Swift 3.x
This is a bit detailed, so I'd like to leave it in a full answer. This is the most common reason I have encountered for a nil location, since figuring out the basics, a few years ago. So, you call CLLocationManager.startLocating(), in your viewDidLoad. Then you call the method that sets up your map. Sometimes this works, and sometimes it doesn't, because of a race condition caused by the amount of time it takes the CLLocationManager to set up permissions, on the one hand, and access the user's location, in another part of the code. Let's look at an order of events, where it doesn't work:
1) you call requestAlwaysAuthroization and startLocating
2) User permissions setup is triggered on one thread
3) In your ViewController, you request the user's location, to set up your map
4) It comes back nil
5) NOW, step 2 finishes, and the app has access to the user's location, but it's too late
The core problem, is that the process that starts with requesting permissions and location, takes more than a few milliseconds. And if your view is already set up, it takes few milliseconds for it to go through the methods in your viewDidLoad. By the time you have the location you need, you've already requested it. This has caused me too many crashes, in my location-based apps.
My workaround, has been to craft a singleton CLLocationManager, make my starting view a delegate, and requestAlwaysAuthorization and startLocating, in that view. That way, when I get to the view that needs the location, the app has already started locating, and the locationManager.location is not nil.
This is an approach that will obviously not work for every app. If you need clarification, let me know, and if you need code, as well. I have a few public iO git repos, with projects where I have encountered and fixed this problem.

Exception on API Key of Google Maps API for iOS

I am developing an iOS app using Google Maps API for IOS. And I installed the CocoaPod for my project and configure them according to tutorial on Google Developer. However, when I run my project, it says
*** Terminating app due to uncaught exception 'GMSServicesException', reason: 'Google Maps SDK for iOS must > be initialized via [GMSServices provideAPIKey:...] prior to use'
But I already call "GMSServices.provideAPIKey on the AppDelegate.swift. Following is the code:
....
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
GMSServices.provideAPIKey("***********************")
return true
}
....
(**************) is my API Key.
And because Google Maps API use Objective C, so I created a Bridging Header to import the library.
I tried to set breakpoint on [application:didFinishLaunchingWithOption]. But it will raise exception before run that function, which I think is very weird.
So confused about it. Thanks in advance.
Problem finally solved, the reason is that I initialize a fields using Google Maps library in the one model class and it will be created before the app run. So this error happens. When I moved this variable into the method, problem solved. Following is the code that causes error:
class PlaceManager {
let placeClient = GMSPlacesClient()
...
func getSuggestions(queryString:String) -> [String]{
...
}
}
After
class PlaceManager {
func getSuggestions(queryString:String) -> [String]{
let placeClient = GMSPlacesClient()
...
}
}
Instead of didFinishLaunchingWithOptions, move the call to willFinishLaunchingWithOptions. This method is called after state restoration has occurred but before your app’s window and other UI have been presented. (Which in your case might be a UI that consumes Google Map API)
func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
GMSServices.provideAPIKey("***********************")
return true
}
I just had the same problem. I created a GMSMapView object and it was initialized before maybe the api key could be read. So I moved it inside the viewDidLoad method and problem solved.
Before :
class ViewController: ..... {
let mapView = GMSMapView()
After :
class ViewController: ..... {
var mapView : GMSMapView?
override viewDidLoad(){
mapView = GMSMapView()

Google Map flickering in iOS

I am using Google Maps SDK for iOS version: 1.10.17867.0 in my app via pod. But when I initialise the map at a particular position, all the titles and map starts flickering.
Example Code (swift):
import UIKit
import GoogleMaps
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor();
var camera = GMSCameraPosition.cameraWithLatitude(19.0176147, longitude: 72.8561644, zoom:18)
// even try this: 28.6469655, longitude: 77.0932634, zoom:10
var mapView = GMSMapView.mapWithFrame(CGRectZero, camera:camera)
var marker = GMSMarker()
marker.position = camera.target
marker.snippet = "Hello World"
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
self.view = mapView
}
}
I have figured out the reason.
If you are using an incorrect google maps api key, or correct key with insufficient permissions, then this will happen. It was the latter reason for us.
For further reading, documentation link, although the said behaviour is not mentioned anywhere. It should rather log an error message.

Getting Coordinates with CLLocationManager

In my iOS app, I have the following code. With this code I am hoping to get the Latitude and Longitude values of the device's current location.
CODE AppDelegate
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var locationManager: CLLocationManager!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
application.setStatusBarHidden(true, withAnimation: .None)
initializeLocationManager()
return true
}
func initializeLocationManager() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
CODE ViewController
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let localtionManager = appDelegate.locationManager
var currentLat = localtionManager.location.coordinate.latitude
var currentLng = localtionManager.location.coordinate.longitude
let forecastURL = NSURL(string: "\(currentLat),\(currentLng)", relativeToURL: baseURL)
On the third line of code in my ViewController from debugging I can see that the value returned is: 6.9530045620513319E-310.
I have been told that this value can't be right, in other words something has gone wrong. Can you please tell me why this is wrong? and how I can get the latitude and longitude as strings so that I may pass them to a RESTful API?
Thanks
6.9530045620513319E-310 is not a valid value that should be returned for latitude or longitude, so you've most likely made an error somewhere else in your code. Without the rest of your code we can only make guesses as to what you did wrong.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
println(manager.location.coordinate.latitude)
println(manager.location.coordinate.longitude)
}
Try dropping this code into your CLLocationManagers delegate and if it doesn't output a valid latitude and longitude make sure that
You have requested permission to have a users location and have added the reasoning into your info.plist
You have called locationManager.startUpdatingLocation()while settings up your locationManager
If you are using the simulator make sure you have gone to Debug-> Location and set a location
if it still doesn't work you're going to need to post more of your project code so we can figure out where you went wrong.
You just need to add NSLocationAlwaysUsageDescription=true in the app's plist. That did it for me.

Resources