App is experiencing following crash and unable to understand the cause behind of this crash. This crash report I got it from App Store. This is the crash report screenshot
It is mostly affecting on iOS 10.2. In this class I'm using Google Maps, Pageviewcontroller and Timer. So, anyone can tell me how to figure out it?
This crash is happening due to fetching user current location from Google Maps by using addObserver forKeyPath:#"myLocation" options:NSKeyValueObservingOptionNew.
While dealloc Google Maps, that time you need to remove this Observer. Otherwise app will crash with following error
NSInternalInconsistencyException: An instance 0x1759f350 of class GMSMapView was deallocated while key value observers were still registered with it. Current observation info: ( Context: 0x0, Property: 0x177a4490> )
you need to addObserver before adding Google Maps to mapView like following:
// Listen to the myLocation property of GMSMapView.
[mapView_ addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
self.view = mapView_;
// Ask for My Location data after the map has already been added to the UI.
dispatch_async(dispatch_get_main_queue(), ^{
mapView_.myLocationEnabled = YES;
});
#pragma mark - KVO updates
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (!firstLocationUpdate_) {
// If the first location update has not yet been received, then jump to that
// location.
firstLocationUpdate_ = YES;
CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
mapView_.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
zoom:14];
}
}
then add this code also for removing the observer
- (void)dealloc {
[mapView_ removeObserver:self
forKeyPath:#"myLocation"
context:NULL];
}
for more details: Google Maps iOS SDK, Getting Current Location of user
Related
Im having issues with this KVO-coding. In the code below I was first scanning for changes in key currentLocation, which was working fine but yet was calling getData twice, because, I presume, CLLocation has both altitude and longitude and hence changes twice. Okay, I thought I could neatly just scan either of those:
-(void)viewWillAppear:(BOOL)animated{
dataManager = [[DataManager alloc]init];
[dataManager addObserver:self forKeyPath:#"currentLocation.altitudeā
options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context{
//if(context==locationContext)
location = [object valueForKeyPath:keyPath];
//If scanning just currentLocation will get 2 events send....
if([keyPath isEqualToString:#"currentLocation.altitude"]){
if(location != nil){
//connect and get data (if location changed more than WILL BE SPECIFIED
[dataManager getData];
}
}
}
But now I start getting following error msg, which I didn't see before:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x1742050d0 of class CLLocation was deallocated while key value observers were still registered with it.
When an observer is deallocated, the NSNotificationManager doesn't figure it out, and when it wants to send a message, it sends it to the deallocated observer - and then things go wrong.
You typically add code to your dealloc that unregisters your object from the notification manager.
I am writing you because I am stuck with a super strange error.
I tried to add GMS on my app, and finally, when I have to get device location, I am stuck with this crash:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7ff7fd82def0 of class GMSMapView was deallocated while key value observers were still registered with it. Current observation info: (
Context: 0x0, Property: 0x7ff7fdc2f470>
Code is initialized here:
self.mapView.myLocationEnabled = YES;
self.mapView.mapType = kGMSTypeNormal;
self.mapView.settings.compassButton = YES;
self.mapView.settings.myLocationButton = YES;
//=> Listen to the myLocation property of GMSMapView.
[self.mapView addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqualToString:#"myLocation"] && [object isKindOfClass:[GMSMapView class]])
{
appDelegate().curUserLocation = [change objectForKey:NSKeyValueChangeNewKey];
[self.mapView animateToCameraPosition:[GMSCameraPosition cameraWithLatitude:self.mapView.myLocation.coordinate.latitude
longitude:self.mapView.myLocation.coordinate.longitude
zoom:15]];
}
}
and still no success. I put breakpoint in observerValueForKey method, and once is out from here, crash appears. No way to get the idea.
I also removed observer :
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.mapView removeObserver:self forKeyPath:#"myLocation"];
//=> Set map delegate to nil (to avoid: mapView:regionDidChangeAnimated:]: message sent to deallocated instance )
self.mapView.delegate = nil;
self.mapView = nil;
}
and no success.
Can anyone help me with this ? I tried all possible solutions, but no way.
Thanks in advance!
How already said in comment.. the GMSMapView must be Strong
Your code will not work in iOS 8 if you not call requestWhenInUseAuthorization
I recommend you to use only the CLLocationManager instead KVO... but is your decision.
Attached my example - I modified the Google example... with 2 example:
with KVO
only with CLLocationManager
If you have any issues... just let me know
PS Don't forget to add you API Key
Happy coding!
UPDATE
if you startUpdatingLocation.. don't forget to stop it somewhere with stopUpdatingLocation.. let say in ViewDidDisapear
If you register inside viewWillAppear:, use viewWillDisappear to remove observer.
If you register inside viewDidLoad, use deinit to unregister the observer. Always use the counter part to register and unregister and that should be fine
Swift 3
deinit {
mapView.removeObserver(self, forKeyPath: "myLocation")
}
I try to get the direction from current location to other point using Google Map API. Everything is OK when i input the origin point and destination point manually. But, when i try to set the origin point as current location, the location is null as the following code:
mainMap=[[GMSMapView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithTarget:[mainMap.myLocation coordinate] zoom:13];
mainMap.camera=camera;
mainMap.myLocationEnabled=YES; // <---- The blue point appear on map: it's exactly my location
[self.view addSubview:mainMap];
//Get mylocation
CLLocation *myLocation = mainMap.myLocation; // <----- NULL
Is there any body know what is my problem here? Tks a lot
The thing is: Getting a location is asynchronous and how you do it is expect it to block till its there... which is not how it works
you have to add a KVO observer inn the map and observer myLocation.
Then when your observe method gets called, you get the myLocation.
(that's how the blue dot works too :))
- (void)viewDidLoad {
//...
[self.mapView addObserver:self forKeyPath:"myLocation" options:0 context:nil];
}
- (void)dealloc {
[_mapView removeObserver:self forKeyPath:#"myLocation"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:#"myLocation"]) {
CLLocation *l = [object myLocation];
//...
}
}
Hi i am using the below code to display current location on the map. I notice that the current location does not seem to be updating when i travel around. I would like the location indicator to update the pointer according to the place i travel. How would i go about doing this? Currently only able to display the current location on the map and that is it.
[self.mapView.locationDisplay startDataSource];
self.mapView.locationDisplay.autoPanMode = AGSLocationDisplayAutoPanModeCompassNavigation;
You might Listen for location updates:
- (void)registerAsObserver {
[ self.mapView.locationDisplay addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew)
context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqual:#"location"]) {
NSLog(#"Location updated to %#", [self.mapView.locationDisplay mapLocation]);
}
}
Try specifying wanderExtentFactor - add one more line of code, wanderExtentFactor can take values from 0 to 1 just play around to see which settings suit you best
[self.mapView.locationDisplay startDataSource];
self.mapView.locationDisplay.autoPanMode = AGSLocationDisplayAutoPanModeCompassNavigation;
self.mapView.locationDisplay.wanderExtentFactor = 0.5;
I have a GMSMapView properly loaded and working inside my viewcontroller
what i'm not being able to do is setting the GMSCameraPosition around my location
this is my code:
mapView_.myLocationEnabled = YES;
CLLocation* myLoc = [mapView_ myLocation];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:myLoc.coordinate.latitude
longitude:myLoc.coordinate.longitude
zoom:4];
[mapView_ setCamera:camera];
GPS is enabled and application has all needed permissions but myLocation returns a nil CLLocation, consequentially cameraWithLatitude:longitude:zoom: get 0 0 coordinates and displays Africa instead of my actual location (that is not in africa :) )
From official Google Maps iOS SDK documentation:
(BOOL) myLocationEnabled [read, write, assign]
Controls whether the My Location dot and accuracy circle is enabled.
Defaults to NO.
(CLLocation*) myLocation [read, assign]
If My Location is enabled, reveals where the user location dot is being drawn.
If it is disabled, or it is enabled but no location data is available, this will be nil. This property is observable using KVO.
So when you set mapView_.myLocationEnabled = YES;, it only tells the mapView to reveal the blue dot only if you have a location value given to the myLocation property. The sample code from Google shows how to observe the user location using the KVO method.(Recommended) You can also implement the CLLocationManagerDelegate method, to update the mapView.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[mapView animateToLocation:newLocation.coordinate];
// some code...
}
Here are the code from google maps sample code on how to use KVO to update user location.
// in viewDidLoad method...
// Listen to the myLocation property of GMSMapView.
[mapView_ addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
// Ask for My Location data after the map has already been added to the UI.
dispatch_async(dispatch_get_main_queue(), ^{
mapView_.myLocationEnabled = YES;
});
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (!firstLocationUpdate_) {
// If the first location update has not yet been recieved, then jump to that
// location.
firstLocationUpdate_ = YES;
CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
mapView_.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
zoom:14];
}
}
Try to using MapKit, under the VieDidLoad or ViewWillApper using:
myMapView.showsUserLocation = YES;
You can add this simple code under the IBAction if you want, like a :
- (IBAction)getLocation:(id)sender{
myMapView.showsUserLocation = YES;
}
I hope this help you