ios Mapview properties are not persisting - ios

I am trying to use the mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated method to limit the region of my mapview but whenever I make a call to my mapview's region ([self.userMapView setRegion:regionLimit] ), it gives me a EXC_BAD_ACCESS error.
This error is thrown no matter what property I try to call from my mapView. I have my mapview set to the mapview with a proper outlet, and I was even able to call the set region in the viewDidLoad message.
How can I keep these properties from throwing the bad access error? If no can answer, can anyone direct me to a resource explaining how to debug something like this? Thanks.

See here for his to debug EXC_BAD_ACCESS errors and common mistakes that cause them. In your case, I'll bet your property is long dead and recycled, or was never initialized in the first place.

Related

Issues with Multiple MKMapViews in IOS Application

I've been having an issue with having multiple MKMapViews in my iOS application.
We are currently using a TabBarController for basic navigation. The issue comes up when a MKMapView's annotation's button segues to another view that has a button that leads to another MKMapView. The first MKMapView works fine with annotations and functionality, but the second MKMapView won't add annotations.
I believe the class is linked to the StoryBoard's layout fine since it triggers the viewDidLoad function upon the segue. When I step through the viewDidLoad function it reaches the addAnnotation function call, but the annotations do not get added to the map.
I know the post "Multiple map views in same app" covers a similar issue, but the poster didn't seem too friendly and didn't get any answers due to that.
Please let me know what you think, if you need more information, or if you've implemented multiple MKMapViews in your iOS project. Thanks!
Look closely at your setup of delegates & IBOutlets to make sure each view is pointing to the right mapview. Then make sure each function uses the parameters it was given, e.g.
- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id < MKAnnotation >)annotation
{
//Only use "aMapView here not "mapView"
}

didUpdateUserLocation not called when view for userLocation is custom

I have an MKMapView that's supposed to track the user's location using a custom view (not the blue dot). In order to substitute this view for the blue dot, I return it thusly:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (annotation == [mapView userLocation])
{
return userLocationView;
}
}
To initialize tracking, I call
[mapView setShowsUserLocation: YES];
[mapView setUserTrackingMode: MKUserTrackingModeFollow animated: NO];
[mapView setDelegate: self];
As would be expected, -mapView:didUpdateUserLocation: gets called once when the app loads. Unfortunately, it's never called again unless I change -mapView:viewForAnnotation: to have the following implementation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (annotation == [mapView userLocation])
{
return nil;
}
}
With these changes, the map loads the blue dot as the indicator of the user's location, and -mapView:didUpdateUserLocation: gets called frequently, as would be expected.
Is there some sort of mutual exclusivity for tracking users' locations and have a custom user location view? How can I make both happen?
Source
This project demonstrates this issue. https://dl.dropbox.com/u/2338382/MapKitFuckery.zip
Bug
This is most likely a bug, which I've filed as a radar. In the interim, the accepted answer should prove sufficient. However, it bears noting that I had to give up entirely on [mapView userLocation] and [mapView showsUserLocation], in favor of simply a custom annotation and the CLLocationManager.
Instead of relying on the map view's location updates, start a CLLocationManager, set its delegate and wait for -locationManager:didUpdateToLocation:fromLocation: (in iOS 5 and lower) or -locationManager:didUpdateLocations: (iOS 6). You will get much more reliable and plentiful information than using the map view's delegate methods. You probably know the way to do this, but here it is:
#import <CoreLocation/CoreLocation.h>
- (void)viewWillAppear:(BOOL)animated
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager startUpdatingLocation];
}
// Deprecated in iOS 6
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// Check the age of the newLocation isn't too long ago using newLocation.timestamp
// Set the map dot using newLocation.coordinate
// Set an MKCircle to represent accuracy using newLocation.horizontalAccuracy
}
I had a look at the delegate calls that come in to the mapView's delegate, and returning anything other than nil stops calls to -mapView:didUpdateUserLocation:, like you said. Here are the calls in the order they arrive:
- (void)mapViewWillStartLocatingUser:(MKMapView *)mapView
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
- (void)mapViewWillStartLoadingMap:(MKMapView *)mapView
- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error
Presumably the MKUserLocation object, not the MKMapView is the object responsible for calling the delegate with update calls. If you check the status of showsUserLocation and mapView.userLocation, they both look fine:
NSLog(#"%d %#", mapView.showsUserLocation, mapView.userLocation);
returns 1 and a non-nil object (1 <MKUserLocation: 0x1e02e580>). Maybe the mapView queries its userLocation object to get the current location, then sends it to the delegate. If that object has gone, it won't work.
It's a bit strange, but like I said, you'll get better updates from a CLLocationManager's updates.
An old question that I would like to answer my own way. I was having an issue somewhat similar. I just needed to make a web service call, passing the user location as a GET parameter, when my MapView's ViewController/Screen was loaded and user location retrieved by the mapView. It made sense then to call the web service within the delegate method didUpdateUserLocation. I didn't notice the wrong behaviour first because things seemed to work properly but then for some reasons sometimes upon opening the mapView screen, the user blue dot would show but the map would not "zoom in" and neither didUpdateUserLocation was called nor my inner web service call obviously. After a few seconds of staring at the screen, the map would "zoom in" and the didUpdateUserLocation/web service was called. Some small glitch I thought, not a big deal. Now my detail-oriented developer's mind was still frustrated and after a few weeks of thinking this over, I decided to take action on this. Stackoverflow didn't give me the answer straight away but pointed me towards the right direction nonetheless. And here was the culprit: Sequence of calls! Maddening but made total sense once I figured things out. I knew that in order to see the blue dot and get the user location I had to tell the mapView to do so. So being an Interface Builder lover, I set things up properly for my mapView in IB, that is I checked the box: "User Location", easy. Then carefully reading the mapView documentation I realised that my ViewController needed to conform to MKMapViewDelegate, done deal. As I said, things seemed to work ok, the blue dot would show right away but sometimes the "zoom in" of the map would take a few seconds... well my iPhone is already 3 years old, things are getting slow, I'd deal with the sluggishness... Then I read this stack overflow post (https://stackoverflow.com/a/37407955) and things became clear. In my case, since using IB, here was the sequence of calls:
User Location checkbox checked in IB
In viewDidLoad, call: mapView.delegate = self
Whereas, here is how the sequence of calls should have been:
User Location checkbox NOT checked in IB (This is important)
mapView.delegate = self
mapView.showsUserLocation = true
And this changes EVERYTHING. Instead of having the mapView zooming in sometimes right away and sometimes after a few seconds, the mapView now zooms in right away when the screen opens, and the didUpdateUserLocation/web service IS called.
Now a little more on the why, it still "sometimes" worked. This is simply due to the fact that the location of my iPhone was sometimes updated right after the map screen was loaded and sometimes not :-). I have to say that besides the stackoverflow post I mentioned above, what helped me too was testing my app in the Simulator since I needed to use a gpx file with obviously static location coordinate, the non predictable behaviour I described was then systematic.
So as much as I love Interface Builder, I might have to reconsider how unconditional that love is.
PS: I know this post is old and my answer not entirely related to the issue #Patrick Perini had but I wish it helps others and that it might answer #Patrick Perini's conclusion regarding the fact that a Bug was at fault when it's not. Thanks for reading this blog post :-)

App Crashes if AddAnnotations doesn't finish

I have an Application, which is a SplitViewController that has a master view on the left and the detail view on the right. One of the views (Branch Finder) is a Map view that loads a series of Annotations to the Map.
If I let the annotations load before switching to any other view (loading the annotations take takes all of 1 second) then everything is fine. However, if the user quickly switches off the Branch Finder view, whilst the annotations are being loaded, then the App will crash with the following notice:
[BranchFinder_iPad respondsToSelector:]: message sent to deallocated instance 0x807d230
Now, my thoughts are that the deallocated instance would refer to the Array (declared in the header of the view) that contains all the annotations being released and set to nil when the user leaves the BranchFinder_iPad view. This is the array that is being passed to the addAnnotations method.
[self.mapView addAnnotations:branchSites];
Has anyone else encountered an issue where leaving a view, mid-way in the add allocations and a crash occurs if the user moves to another view.
Just to clarify:
If I wait for the annotations to load, switching to any other view causes no problem.
I did have a custom annotation view, but I stripped that out of my code (to eliminate it from the mix). Doing this has not changed anything.
I have looked elsewhere for help on this issue, but a lot of the view tutorials regarding map views are single view only, so this issue hasn't arisen.
I have found a vaguely similar issue # the following: mapkit addAnnotations crashes
And finally, I have just made the jump to x-code 4. I think some of my problems are just because I'm relearning some of the things I should know.
Regards,
Nathan A
PS: I wanted to attach an image to this, but am having trouble. I don't have the reputation points to do it natively, and my workplace doesn't allow me access to any image hosting portals. I will endeavour to add an image later today.
Hey anyone who reads this.
I basically performed a rookie mistake here - for the MKMapView in my application, I had to set the delegate to nil as part of the deallocation routine within my view. THe apple documentation makes mention of this in the below document:
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapViewDelegate_Protocol/MKMapViewDelegate/MKMapViewDelegate.html
For the relevant section:
Before releasing an MKMapView object for which you have set a delegate, remember to set that object’s delegate property to nil. One place you can do this is in the dealloc method where you dispose of the map view.
Not having this was only causing an issue if I switched to another view AND if the MKMapView was still being referenced in executing code, such as the addAnnotations routine.

Warning in Custom Map Annotations iPhone

I am using a custom map annotation class for map view in iPhone. Whenever I pop my map view from navigation bar stack I usually see some warnings in console.
MapAnnotation was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
I am not using KVO in my code hence not able to understand why I am receiving these warnings
Latitude and Longitude have differing bounds:
(-90, 90) for Lat
(-180, 180) for Long
Passing a value outside of those bounds will cause the custom class to be deallocated and therefore giving you the error that you're receiving. Make sure that you are passing the correct values for both Latitude and Longitude.
It would be really nice if Apple passed a bounding error for this instead of an early release error. That would've saved me roughly 5 hours worth of time
I was getting the same error as you:
An instance 0xa975400 of class xxxxxx was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0xa980eb0> (
<NSKeyValueObservance 0xa980e70: Observer: 0xa94f8a0, Key path: coordinate, Options: <New: NO, Old: NO, Prior: YES> Context: 0x0, Property: 0xa980ef0>
As pointed here it was caused because I was adding a MKAnnotation with an invalid coordinate to a MKMapView.
My solution was to create a function to check the coordinate valid.
Place+MKAnnotation.m
I created a category of my Place class and
#import "Place.h"
#import <MapKit/MapKit.h>
#interface Place (MKAnnotation) <MKAnnotation>
- (BOOL)coordinateIsValid;
...
#end
Place+MKAnnotation.m
#implementation Place (MKAnnotation)
- (BOOL)coordinateIsValid
{
return CLLocationCoordinate2DIsValid(CLLocationCoordinate2DMake([self.latitude doubleValue],[self.longitude doubleValue]));
}
...
#end
I only add the annotation in my ViewController if the coordinate is valid.
if([p coordinateIsValid]) {
[self.mapView addAnnotation:p];
}
Fixed it. I was using a wrong pair of latitude and longitude in annotations, I have changed the same and now everything seems to be perfect and warning has been disappeared as well.
Are you autoreleasing your annotation before adding it to the MapView?
If so, try just allocating it, add it to the MapView, then release it.

Observing the region of MKMapView via KVO?

I have an object that is interested in knowing when the region of a MKMapView is changed. This object is not the delegate of the map view, however. I'm trying the following, where map is a MKMapView:
[map addObserver:self forKeyPath:#"region" options:0 context:nil];
However, observeValueForKeyPath:ofObject:change:context: isn't being called back.
As an interim solution, I have the map's delegate letting this other object know when the map region is changed, but I'd like to uncouple the two objects as they aren't really related.
In Cocoa (Touch), properties of framework objects are only guaranteed to be KVO-compliant if the documentation says so. The docs for -[MKMapView region] make no such claim, so you shouldn't try to use KVO upon it. Even if it happened to work, you'd have no guarantee of complete compliance, or of continued success.
Instead, you'll have to use the delegate method and message other objects from there. Possibly your delegate could broadcast an NSNotification to achieve a similar effect to KVO.

Resources