After adding annotation and if user put app in background, after 1 second it crashes. In foreground it is not crashing. It does not show in logs about crash.
Adding a annotation from viewDidLoad() method
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: lat as! Double, longitude: long as! Double)
mapView.addAnnotation(annotation)
Delegate method code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let pin = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.canShowCallout = true
let button = UIButton(type: .detailDisclosure)
pin.rightCalloutAccessoryView = button
return pin
}
Crash log:
Please let me know what I am doing wrong.
UPDATE
Even after created a new project with simply adding an annotation in MKMapView. It behaves the same as mine. Is it global framework issue? Any other guys faced/facing?
Please Help!
Using expressions like lat as! Double is almost always a bad idea.
Try something like if let lat = lat as? Double and make a nice error handling if that fails.
I am trying to add map annotation, but when i try to run the app, the map annotation doesnt show, and give error message.
Add Map Annotation[3668:68848] Could not inset legal attribution from
corner 4
actually I just follow along a tutorial on Youtube in here https://www.youtube.com/watch?v=hRextIKJCnI , in swift3 this code seems work, but I don't know why it doesnt work in me. I am using swift 4 and Xcode 9.2
I have tried a solution from stack overflow but it doesn't work in me, in here Could not inset legal attribution from corner 4 swift
What went wrong in here?
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapKitView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let span : MKCoordinateSpan = MKCoordinateSpanMake(0.001, 0.001)
let location : CLLocationCoordinate2D = CLLocationCoordinate2DMake(-6.239116, 106.789415)
let region : MKCoordinateRegion = MKCoordinateRegionMake(location, span)
mapKitView.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.title = "My Shop"
annotation.subtitle = "Come visit here"
mapKitView.addAnnotation(annotation)
}
}
You are saying:
let annotation = MKPointAnnotation()
annotation.title = "My Shop"
annotation.subtitle = "Come visit here"
mapKitView.addAnnotation(annotation)
And that's all you're saying. But... That annotation has no coordinate! So how do you imagine the map can possibly know where it's supposed to go?
So I want to make a button that sets an annotation at your current location. I have all of my map stuff and core location code working it is just the button. Here is my button function code:
#IBAction func addAnnotation(_ sender: UIButton) {
CLLocationManager().startUpdatingLocation()
let annotation = MKPointAnnotation()
// Set the annotation by the lat and long variables
annotation.coordinate = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
annotation.title = "User location"
self.map.addAnnotation(annotation)
}
Right now, I When I run this code I get a SIGABRT Error in my AppDelegate.swift. Please Help.
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.
I'm building a basic geofence app that allows users to create geofences, view them on a MKMapView, and activate and deactivate them. It is based on the Ray Wenderlich tutorial, but I have adapted it in several ways. Namely, I am using Realm to persist data and I have created a separate LocationHandler class that acts as LocationManagerDelegate and holds a LocationManager. Generally, I tried to move some functions out of viewControllers and into separate classes.
Everything seems to work, except periodically map annotations and overlay aren't rendered correctly in the simulator. About 20% of the time annotations and overlays won't be removed when they should be. Or, colors won't change as they should. Or, a circular overlay will change colors, but the associated pin won't.
Is this due to some error in my code, or is this an artifact of using a simulator?
Thank you for your help
Edit to add some code:
In view controller
//Clicking the 'x' deletes the geofence
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let anAnnotation = view.annotation as! GeofenceAnnotation
let geofence = anAnnotation.geofence
//stop monitoring geofence
locationManager.stopMonitoringGeofence(geofence!)
//remove representation of geofence from map
removeGeofenceRadiusCircle((geofence?.identifier)!)
mapView.removeAnnotation(anAnnotation)
//delete geofence from realm
try! realm.write {
realm.delete(geofence!)
}
updateGeofenceCount()
}
//Go through all overlays and remove appropriate one
func removeGeofenceRadiusCircle(id: String) {
self.mapView.delegate = self
if let overlays = mapView?.overlays {
for ol in overlays {
if let circleOverlay = ol as? GeofenceRadiusCircle {
let aId = circleOverlay.id
if aId == id {
mapView?.removeOverlay(circleOverlay)
break
}
}
}
}
}
subclass of MKAnnotation
class GeofenceAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
var geofence: Geofence?
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, geofence: Geofence? = nil) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.geofence = geofence
}
subclass of MKCircle
class GeofenceRadiusCircle: MKCircle{
var geofence: Geofence?
var color: UIColor?
var id: String = ""
}
It seems like it was a little bit of an error on my side and also maybe an error with the simulator. I needed to remove the old overlay before redrawing in viewWillAppear to account. That seemed to solve the overlay and annotation problems. I also had a problem with the user location not showing all the time in the mapView and that doesn't seem to be the case when I run the app on my phone.