I am facing an issue about MKMapView delegate.
In iOS5, When I clicked a Pin on the mapview,
thedidSelectAnnotationView: delegate will be called first,
and the next is viewForAnnotation: delegate called.
In iOS6, When I clicked a Pin on the mapview,
the viewForAnnotation: will be called first, and the next is didSelectAnnotationView delegate called.
So my app works fine in iOS5, but works bad in iOS6,
it's because that there are coordinate informations that I need setting in the didSelectAnnotationView: delegate,
If viewForAnnotation: delegate are called before the didSelectAnnotationView:, then I'll get the wrong coordinate information.
Anybody got some idea? thank you!
viewForAnnotation can and will be called when ever iOS needs to display one of your annotations. It is not related to when didSelectAnnotationView is called. You may think you found a pattern in iOS 5 but that was just a fluke of something in your app and should never have been relied on. If you use it correctly it will work in iOS 5 and 6 as well as 6.1, 6.2, 6.anything and I'd guess they won't change it much to iOS 7 either. If you look in the signature of viewForAnnotation you'll see that one of the parameters is an annotation. That is the item that your app is trying to draw and it has what ever information you gave the annotation when you called [mapView addAnnotation:myAnnotation]. So cast it to your MKAnnotation implementation and extract the info.
modify the logic.
Prepare the view in viewForAnnotation (which in theory -- can be called at any time anyway). It is the right place for this!
"The annotation view to display for the specified annotation or nil if you want to display a standard annotation view."
Related
I know there is already a question similar to this on SO (Displaying info window when tapped marker in google maps iOS sdk while implementing mapView:didTapMarker: delegate method implemented) but the answer does not apply in my case.
In my mapView(didTap:) delegate method, it has to return true because I programmatically determine the camera position when a marker is tapped. If I return true like the answer in the above question says, the map is automatically centered on the selected marker, which I do not want. Since I return true, tapping a marker does not display the marker's information window, which I still want to occur, so is there a way for me to do that programmatically?
I don't think the code in my mapView(didTap:) delegate method is necessary for answering this question, but if anyone needs it, let me know. (Keep in mind that my question question refers to the delegate method for when a marker is tapped, not the delegate method for when an info window is tapped, mapView(didTapInfoWindowOf:))
Thanks in advance.
Edit:
Looking through the Google Maps Documentation, I found out that there is a method for what I am looking for in JavaScript called showInfoWindow() that you call on the marker who's info window you want to show (this is the link to the documentation I'm talking about). So does anyone know a Swift 3 alternative to this method?
Edit:
If I return false in the delegate method, the camera instantly moves to the marker's location for a split second, and then pans over to the location I programmatically tell it to move to. This technically works, but it is ugly and not fluent, so I still need a way to programmatically show the marker's information window while the delegate method returns true.
After going on google's issue tracker and submitting a post, I found out that mapView.selectedMarker() = marker does not actually have any connection to the mapView(didTap:) delegate method, so returning true in the delegate method has no impact on the selectedMarker() method's functionality.
As a result I can just add mapView.selectedMarker() = marker in the delegate method after customizing the location I want to animate the mapView to and before returning true, which causes the marker's info window to pop up without messing with the camera position.
I'm displaying a MKMapView with MKAnnotations some of which are selected and showing their Annotation.
I am trying to grab an image of the displayed map and annotations using the -renderInContext.
90% of the time the Map, MKPinAnnotationView's and selected annotations are correctly captured.
The other 10% of the time the image is missing something, usually the MKPinAnnotationViews or their annotations if selected.
I've added code to deal with the Map itself loading it's map data.
But I haven't been able to track down something that would indicate to me that all of the visible MKPinAnnotationView's have been drawn
and if selected their annotations displayed??
the closest hint I've come across is the addObserver, although I haven't figured out what could be observed that would tell me when all of the drawing is done.
Thoughts?
ok I'm an idiot...
I finally tracked down the problem. In my viewForAnnotation routine in the MKMapView Delegate protocol I wasn't correctly setting values for reused MKPinAnnotationView's.
So some of the time I would reuse a view that had .canShowCallout set to YES and other times I'd reuse a view that had .canShowCallout set to NO.
.<
Try using the MKMapViewDelegate didAddAnnotationViews method.
If in that method, the drawing is still not ready for your requirements, you could then in there call your capturing method with performSelector:withObject:afterDelay:.
I have an interface with a mapView and UITableView. Data is loaded from a server, and the annotations are created and added to the map with
[mapView addAnnotation:truck]
the tableview is then populated using the array thats retured from
[mapView annotations]
once this process is completed, i check the number of annotations on the map with [[mapView annotations] count] called whenever i click on a cell in the table and its equal to the number it ought to be, so all the annotations are getting added onto the mapView, but for some reason I cant see any annotations in the simulator.
The images are named just as they are assigned in the custom AnnotationView, the loadAnnotation function is done properly, etc... i dont know what it could be but ive looked at the associate between the image file and wheres its loaded a hundred times to find a discrepancy, but it all looks fine.
One interesting point is that when i print and coordinate value after clicking on the cell (remember this data comes straight from [mapView annotations], it looks good... but for whatever reason the annotation view isnt being displayed.
so i suppose if i could have the answer to one question it would be, what are possible causes for a mapView to contain several annotations, but to not show any on the map?
Thanks
EDITED WITH IMPORTANT ADDITIONAL INFO
There appears to be a disconnect between what is being displayed on my map in the simulator and what im seeing in the mapView object. For example, when i select a row in the tableView, I am calling:
[mapView setRegion:MKCoordinateRegionMake([annotation coordinate], MKCoordinateSpanMake(.01, .01)) animated:YES];
and this has no effect on the map in the simulator. I have checked that the coordinate being passed is actually a valid coordinate, but it doesnt seem to matter because the map is being unresponsive. I thought it could be something wrong with my .xib, but its all connected properly. delegate is the outlet and mapView as a referencing outlet.
Does anyone now understand what may be happening?
This really looks like missing images.
Try replacing your custom annotations with MKPinAnnotations to test, and see if your annotations are visible then.
Have you implemented the following delegate function ?
(MKAnnotationView*) mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation;
This line:
mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
was creating messing everything up. once i commented it out, the app began working fine.
What are single-state and two-stage animation for rotating an iPhone window?
This is the "error" message I get in the Debugger Console (nothing crashes):
Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
I was working through the book "Beginning iPhone Development: Exploring the iPhone SDK" by Apress (Dave Mark, Jeff LaMarche) on the Swap Project.
Everything is explained in the UIViewController Class Reference. Especially check out the View Rotation section near the top.
From the reference:
Handling View Rotations
By default, the UIViewController class
displays views in portrait mode only.
To support additional orientations,
you must override the
shouldAutorotateToInterfaceOrientation:
method and return YES for any
orientations your subclass supports.
If the autoresizing properties of your
views are configured correctly, that
may be all you have to do. However,
the UIViewController class provides
additional hooks for you to implement
additional behaviors as needed.
To temporarily turn off features that
are not needed or might otherwise
cause problems during the orientation
change, you can override the
willRotateToInterfaceOrientation:duration:
method and perform the needed actions
there. You can then override the
didRotateFromInterfaceOrientation:
method and use it to reenable those
features once the orientation change
is complete.
If you want to perform custom
animations during an orientation
change, you can do so in one of two
ways. Orientation changes used to
occur in two steps, with notifications
occurring at the beginning, middle,
and end points of the rotation.
However, in iPhone OS 3.0, support was
added for performing orientation
changes in one step. Using a one-step
orientation change tends to be faster
than the older two-step process and is
generally recommended for any new
code.
To add animations for a one-step
orientation change, override the
willAnimateRotationToInterfaceOrientation:duration:
method and perform your animations
there. To use the older two-step
method, override one or both of the
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
and
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
methods to configure your animations
before each step. You must choose only
one technique and override just the
methods associated with that
technique. If you override either
method associated with the two-step
technique, the view controller uses
that technique by default.
I have found the culprit in my case to be the UIImagePickerController (I also do not override any rotation animation):
[self presentModalViewController:imagePicker animated:YES];
Replacing imagePicker with a generic UIViewController doesn't generate any warnings.
I changed from willAnimateFirstHalfOfRotationToInterfaceOrientation:duration: method to willAnimateRotationToInterfaceOrientation:duration: method and warning gone.
Thanks.
Ed Marty's answer is the correct one. The reason it will happen if you are not overriding any of the rotation animation is probably that you reply "YES" to shouldAutorotate.. for some view. If you do not implement rotation at all, then you should just not override the shouldAutorotate.. method. If you do override that method, then just override the single step rotation method as well and pass it along to the super.
If you're using iOS 4 and you're getting this warning, I found a way to get rid of it. In your info.plist, there is an item called "Supported interface orientations." Select which orientations your application supports and two-stage warnings will go away when bringing up the imagePicker.
#plumiscles answer didn't quite work for me - there was no item called 'Supported Interface Orientations', probably b/c it is an old project. But you can get the same effect by editing the .plist file directly and adding this:
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationPortrait</string>
Need to add UIImagePickerController as a subview to solve this error
[self.view addSubview:picker.view];
[self presentModalViewController:picker animated:NO];
I've had this issue after creating a tabbarcontroller with no view controllers inside (no tabs), this warning disappeared once I attached at least one view controller to it.
I wasn't over riding any of those two-step functions, but I was calling my own function when I received orientationChanged notifications, and I had this line of code in it. Commenting it out got rid of the warning and allowed the auto rotate to work properly. Auto rotate still worked with this line of code until iOS 4.2, then it broke completely. Spent a lot of time looking for why the built in autoRotate stopped working in 4.2. Maybe this will help someone else.
Commented out this line to make it work:
[[UIApplication sharedApplication] setStatusBarOrientation:currentOrientation animated:YES];
I've delete from plist "Supported interface orientations" row and warning disappears.
I just had the same problem. In my case was a silly mistake that I'm putting here just in case anyone else falls into that same issue.
In my tabbed app I remove one of the original ViewControllers and added a new one with Storyboard to create a "Settings" section.
This new VC had to be a table view VC and even I designed, compiled and run it without a problem, when I changed the orientation of the app I kept getting this “Using two-stage rotation animation” error.
My problem was that I forgot to change in the original .h file interface "UIViewController" for "UITableViewController".
Once this was done I changed on the Storyboard identity badge the class from the general value to my SettingsViewController and that was the end of it.
I hope it can help someone else. It took me a while to get to bottom of this.
Cheers,
I have a MKMapView. Sometimes after my view controller is dismissed, I'll get a EXC_BAD_ACCESS.
I turned on NSSZombies and it looks like the MKMapView's delegate — my view controller! — is being called, despite both the MKMapView and UIViewController subclass being freed. I've checked, and my memory management is correct.
What's going on?
This is because of the way MKMapView works. There's an operation pending, so MapKit is retaining the MKMapView and it hasn't actually been deallocated yet. That isn't itself a problem. The problem is that it's still sending messages to your delegate.
The workaround is simple: As part of your view controller's cleanup set the map view's delegate to nil, which will prevent MKMapView from sending messages to it.
This is documented in MKMapViewDelegate Protocol Reference:
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.
Edit: Give Oscar an upvote as well, just below, who provided the documentation quote here.
Given ARC, I suggest this means you should set your map view's delegate to nil in your view controller's dealloc.
OK, this is the confirmation of the answer. It's from the Apple doc, but it's missing from MKMapView. It's only found under the documentation for its delegate protocol:
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.
NOTE: This also applies to UIWebView.
I set the MapView's delegate pointer to nil in the delegate's dealloc method, and our crashes seem to have been eliminated.
Setting the map view's delegate to nil didn't work for me. However, setting showsUserLocation=NO on the delegate worked by making sure no location updates are received.
The problem, in my case, was that first time I launched app I don't press "allow" when prompting for location authorization (accidentally!!).
Uninstalling app and re-installing it, when prompt appear I allow the authorizations and no more crash!