I would like to add a custom image button into the callout of annotations in specific locations. For example searching for starbucks would bring up an annotation marker for starbucks locations, and when the marker is pressed the callout will display a button that then will direct you to another viewcontroller with starbucks information. Right now the annotation displays the address of the location when pressed, how would I change this to displaying a button at custom locations of my choosing? I am very new to xcode and cannot seem to find much helpful information to this relative to how I have designed my app so far. Everything is function as desired except for the fact I do not know where to start to add a button.
here are my ViewControllers
#import "ViewController.h"
#interface ViewController () <UISearchDisplayDelegate, UISearchBarDelegate>
#end
#implementation ViewController {
MKLocalSearch *localSearch;
MKLocalSearchResponse *results;
}
#pragma mark - View Lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self.searchDisplayController setDelegate:self];
[self.ibSearchBar setDelegate:self];
// Zoom the map to current location.
[self.ibMapView setShowsUserLocation:YES];
[self.ibMapView setUserInteractionEnabled:YES];
[self.ibMapView setUserTrackingMode:MKUserTrackingModeFollow];
}
#pragma mark - Search Methods
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// Cancel any previous searches.
[localSearch cancel];
// Perform a new search.
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = searchBar.text;
request.region = self.ibMapView.region;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (error != nil) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Map Error",nil)
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
if ([response.mapItems count] == 0) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"No Results",nil)
message:nil
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
results = response;
[self.searchDisplayController.searchResultsTableView reloadData];
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [results.mapItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *IDENTIFIER = #"SearchResultsCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:IDENTIFIER];
}
MKMapItem *item = results.mapItems[indexPath.row];
cell.textLabel.text = item.name;
cell.detailTextLabel.text = item.placemark.addressDictionary[#"Street"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.searchDisplayController setActive:NO animated:YES];
MKMapItem *item = results.mapItems[indexPath.row];
[self.ibMapView addAnnotation:item.placemark];
[self.ibMapView selectAnnotation:item.placemark animated:NO];
[self.ibMapView setCenterCoordinate:item.placemark.location.coordinate animated:YES];
[self.ibMapView setUserTrackingMode:MKUserTrackingModeNone];
}
#end
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UISearchBar *ibSearchBar;
#property (strong, nonatomic) IBOutlet MKMapView *ibMapView;
#end
You could set a button as the callout accessory view ,in the viewForAnnotation method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationIdentifier = #"Annotation";
if ([annotation isKindOfClass:MKUserLocation.class]) {
return nil;
}
MKPinAnnotationView* pinAnnotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinAnnotationView)
{
pinAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] ;
pinAnnotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotationView.canShowCallout = YES;
}
return pinAnnotationView;
}
then you can use the mapView:annotationView:calloutAccessoryControlTapped delegate method to respond when users tap a callout view’s control and, in this case, redirect to another view controller:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
InfoController *infoController = [[InfoController alloc] initWithNibName:#"InfoController" bundle:[NSBundle mainBundle]];
/*
here you can pass the necessary information to your InfoController
*/
[self.navigationController pushViewController:infoController animated:YES];
[infoController release];
}
In this example I take usage of a UINavigationController to manage navigation through my view controllers.
There are great resources on SO on how to customize the callout view, like here and here. You can also look at Apple's Documentation for MKAnnotationView, especially the subclassing notes and their MapCallouts example.
Related
I've tried reading the google places API. and tried to duplicate their work. But I think I'm missing some steps here.
Here is the code for header my header file.
#class SPGooglePlacesAutocompleteQuery;
#interface GoogleMapViewViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate, MKMapViewDelegate, UISearchControllerDelegate>
{
NSArray *searchResultPlaces;
SPGooglePlacesAutocompleteQuery *searchQuery;
MKPointAnnotation *selectedPlaceAnnotation;
BOOL shouldBeginEditing;
}
#property (strong, nonatomic) UISearchController *searchController;
#property (retain, nonatomic) IBOutlet MKMapView *mapView;
#end
My implementation file
#import "GoogleMapViewViewController.h"
#import "SPGooglePlacesAutocompleteQuery.h"
#import "SPGooglePlacesAutocompletePlace.h"
#interface GoogleMapViewViewController ()
#property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
#end
#implementation GoogleMapViewViewController
#synthesize mapView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
searchQuery = [[SPGooglePlacesAutocompleteQuery alloc] init];
searchQuery.radius = 100.0;
shouldBeginEditing = YES;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.searchBar.placeholder = #"Search or Address";
self.searchBar.delegate = self;
}
- (void)viewDidUnload {
[self setMapView:nil];
[super viewDidUnload];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark -
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [searchResultPlaces count];
}
- (SPGooglePlacesAutocompletePlace *)placeAtIndexPath:(NSIndexPath *)indexPath {
return [searchResultPlaces objectAtIndex:indexPath.row];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"SPGooglePlacesAutocompleteCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:#"GillSans" size:16.0];
cell.textLabel.text = [self placeAtIndexPath:indexPath].name;
return cell;
}
#pragma mark UITableViewDelegate
- (void)recenterMapToPlacemark:(CLPlacemark *)placemark {
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.02;
span.longitudeDelta = 0.02;
region.span = span;
region.center = placemark.location.coordinate;
[self.mapView setRegion:region];
}
- (void)addPlacemarkAnnotationToMap:(CLPlacemark *)placemark addressString:(NSString *)address {
[self.mapView removeAnnotation:selectedPlaceAnnotation];
selectedPlaceAnnotation = [[MKPointAnnotation alloc] init];
selectedPlaceAnnotation.coordinate = placemark.location.coordinate;
selectedPlaceAnnotation.title = address;
[self.mapView addAnnotation:selectedPlaceAnnotation];
}
- (void)dismissSearchControllerWhileStayingActive {
// Animate out the table view.
NSTimeInterval animationDuration = 0.3;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
self.searchDisplayController.searchResultsTableView.alpha = 0.0;
[UIView commitAnimations];
[self.searchDisplayController.searchBar setShowsCancelButton:NO animated:YES];
[self.searchDisplayController.searchBar resignFirstResponder];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SPGooglePlacesAutocompletePlace *place = [self placeAtIndexPath:indexPath];
[place resolveToPlacemark:^(CLPlacemark *placemark, NSString *addressString, NSError *error) {
if (error) {
SPPresentAlertViewWithErrorAndTitle(error, #"Could not map selected Place");
} else if (placemark) {
[self addPlacemarkAnnotationToMap:placemark addressString:addressString];
[self recenterMapToPlacemark:placemark];
[self dismissSearchControllerWhileStayingActive];
[self.searchDisplayController.searchResultsTableView deselectRowAtIndexPath:indexPath animated:NO];
}
}];
}
#pragma mark UISearchDisplayDelegate
- (void)handleSearchForSearchString:(NSString *)searchString {
searchQuery.location = self.mapView.userLocation.coordinate;
searchQuery.input = searchString;
[searchQuery fetchPlaces:^(NSArray *places, NSError *error) {
if (error) {
SPPresentAlertViewWithErrorAndTitle(error, #"Could not fetch Places");
} else {
searchResultPlaces = places;
[self.searchDisplayController.searchResultsTableView reloadData];
}
}];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForSearchString:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (BOOL)searchController:(UISearchController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForSearchString:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#pragma mark UISearchBar Delegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchBar isFirstResponder]) {
// User tapped the 'clear' button.
shouldBeginEditing = NO;
[self.searchDisplayController setActive:NO];
[self.mapView removeAnnotation:selectedPlaceAnnotation];
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
if (shouldBeginEditing) {
// Animate in the table view.
NSTimeInterval animationDuration = 0.3;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
self.searchDisplayController.searchResultsTableView.alpha = 1.0;
[UIView commitAnimations];
[self.searchDisplayController.searchBar setShowsCancelButton:YES animated:YES];
}
BOOL boolToReturn = shouldBeginEditing;
shouldBeginEditing = YES;
return boolToReturn;
}
#pragma mark MKMapView Delegate
- (MKAnnotationView *)mapView:(MKMapView *)mapViewIn viewForAnnotation:(id <MKAnnotation>)annotation {
if (mapViewIn != self.mapView || [annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *annotationIdentifier = #"SPGooglePlacesAutocompleteAnnotation";
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (!annotationView) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
}
annotationView.animatesDrop = YES;
annotationView.canShowCallout = YES;
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[detailButton addTarget:self action:#selector(annotationDetailButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
annotationView.rightCalloutAccessoryView = detailButton;
return annotationView;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
// Whenever we've dropped a pin on the map, immediately select it to present its callout bubble.
[self.mapView selectAnnotation:selectedPlaceAnnotation animated:YES];
}
- (void)annotationDetailButtonPressed:(id)sender {
// Detail view controller application logic here.
}
#end
I am really confused now to my implementation file as I cannot really understand what is in there TBH.plus some codes here are mostly deprecated. Someone care to give a detailed guide about this? or explain to me in layman's term. TIA.
ANSWERED!
Basically my problem was in this function given on the sample project of google places API..
BOOL SPEnsureGoogleAPIKey() {
BOOL userHasProvidedAPIKey = YES;
if (![kGoogleAPIKey isEqualToString:#"AIzaSyA2vs9pJoLrLs6XU8IRVHo7WxiuMufYXl8"]) {
userHasProvidedAPIKey = NO;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"API Key Needed" message:#"Please replace kGoogleAPIKey with your Google API key." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alert show];
}
return userHasProvidedAPIKey;
}
The if statement originally is incorrect that's why it always gives me the wrong value. now its working :) just added the not "!" in if
I have a Navigation Controller from VC1 to VC2. In VC2 I have a mapkit view. In VC2 user search for location. When user click on any annotation it will go back to VC1. Now I want to send back the address in annotation to VC1 as well. In other words I want to pass data from VC2 to VC1. I have seen unwind segue. As I have seen in tutorials I need to Ctrl+drag the item to exit. My problem is I don't have access to the element. This element which fires go back to VC1 is dynamic.
I appreciate if anyone can give me an example of programmatically do this or any other suggestion.
**EDIT**
This element is an annotation, which is dynamic.
- (IBAction)searchLocation:(id)sender {
// Create and initialize a search request object.
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = _nameLocation.text;
request.region = _mapview.region;
// Create and initialize a search object.
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];
// Start the search and display the results as annotations on the map.
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error)
{
NSMutableArray *placemarks = [NSMutableArray array];
for (MKMapItem *item in response.mapItems) {
[placemarks addObject:item.placemark];
}
[_mapview removeAnnotations:[_mapview annotations]];
[_mapview showAnnotations:placemarks animated:NO];
}];
NSString* nameCurrLocation = _nameLocation.text;
NSLog(#"Location is %#",nameCurrLocation);
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinAnnotation == nil )
pinAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinAnnotation.canShowCallout = YES;
//instatiate a detail-disclosure button and set it to appear on right side of annotation
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotation.rightCalloutAccessoryView = infoButton;
}
return pinAnnotation;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
static NSString *defaultPinID = #"myPin";
MKPinAnnotationView *pinAnnotation = nil;
pinAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:view.annotation reuseIdentifier:defaultPinID];
NSLog(#"Text got clicked %#",view.annotation.title);
//From here I want to send view.annotation.title to VC1**
}
You can perform a segue using code.
Ctrl + drag your VC1 to VC2. Give a identifier at your segue.
In code, detect when the pin is tapped then push your controller with the method performSegueWithIdentifier:sender: of your controller and handle it overriding the method prepareForSegue:sender: `
You can have multiple approaches to this, like via delegates, notifications, or passing an instance of parent view to presented view.
Via delegate:
#interface VC1: UIViewController<VC2Delegate>
#property(strong,nonatomic) NSString *changeMe;
#end
#implementation VC1: UIViewController
-(void) showVC2 {
VC2 *vc2 = [[VC2 alloc] init];
vc2.delegate = self;
[navigationController presentViewController:vc2 animated:YES completion:nil];
}
-(void)changeVariable:(NSString*) newValue {
self.changeMe = newValue;
}
#end
#protocol VC2Delegate <NSObject>
-(void)changeVariable:(NSString*) newValue;
#end
#interface VC2: UIViewController
#property(strong,nonatomic) <id>VC2Delegate delegate;
#end
#implementation VC2: UIViewController
-(void) annotationClicked:(id) sender {
[self.delegate changeVariable:#"Foo!"];
}
#end
Via notification:
#interface VC1: UIViewController
#property(strong,nonatomic) NSString *changeMe;
#end
#implementation VC1: UIViewController
-(void) viewDidload {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"ChangeMe"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(changeTheValue:)
name:#"ChangeMe"
object:nil];
}
-(void) changeTheValue:(id) sender
{
NSString *newValue = [sender userInfo][#"newValue"];
changeMe = newValue;
}
-(void) showVC2 {
VC2 *vc2 = [[VC2 alloc] init];
[navigationController presentViewController:vc2 animated:YES completion:nil];
}
#end
#interface VC2: UIViewController
#end
#implementation VC2: UIViewController
-(void) annotationClicked:(id) sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"ChangeMe"
object:nil
userInfo:#{#"newValue":#"Foo!"}];
}
#end
I used UISearchController since learning that UISearchDisplayController is deprecated. But now have a problem, integrating with SPGooglePlacesAutocomplete forked library by Chenyuan in GitHub.
I get the search bar when I start typing no results are displayed. What I am also wondering is if UISearchDisplayController is deprecated how, come Chenyuan Demo run without warning or issue of deprecated methods.
Here is my code snippet which I attempted to convert his demo to UISearchController, please tell me where I'm going wrong.
MainViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#class SPGooglePlacesAutocompleteQuery;
#interface MainViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate,
UISearchBarDelegate,
UISearchControllerDelegate,
UITableViewDataSource,
UITableViewDelegate>{
NSArray *searchResultPlaces;
SPGooglePlacesAutocompleteQuery *searchQuery;
MKPointAnnotation *selectedPlaceAnnotation;
BOOL shouldBeginEditing;
#private
CGRect _searchTableViewRect;
}
// Search
#property (strong, nonatomic) UISearchDisplayController *searchController;
#property (strong, nonatomic) MKLocalSearch *localSearch;
#property (strong, nonatomic) MKLocalSearchResponse *results;
#end
MainViewController.m snippet
// setup Search Controller
-(void) setupSearchController {
// The TableViewController used to display the results of a search
UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
searchResultsController.automaticallyAdjustsScrollViewInsets = NO; // Remove table view insets
searchResultsController.tableView.dataSource = self;
searchResultsController.tableView.delegate = self;
// Initialize our UISearchController
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.searchController.delegate = self;
self.searchController.searchBar.delegate = self;
// Hint for the search
self.searchController.searchBar.placeholder = #"Search your destination address";
}
// Setup Search Bar
-(void) setupSearchBar {
// Set search bar dimension and position
CGRect searchBarFrame = self.searchController.searchBar.frame;
CGRect viewFrame = self.view.frame;
self.searchController.searchBar.frame = CGRectMake(searchBarFrame.origin.x,
searchBarFrame.origin.y,
viewFrame.size.width,
44.0);
// Add SearchController's search bar to our view and bring it to front
[self.view addSubview:self.searchController.searchBar];
[self.view bringSubviewToFront:self.searchController.searchBar];
}
continuation of the MainViewController.m
-(void)willPresentSearchController:(UISearchController *)aSearchController {
aSearchController.searchBar.bounds = CGRectInset(aSearchController.searchBar.frame, 0.0f, 0.0f);
// Set the position of the result's table view below the status bar and search bar
// Use of instance variable to do it only once, otherwise it goes down at every search request
if (CGRectIsEmpty(_searchTableViewRect)) {
CGRect tableViewFrame = ((UITableViewController *)aSearchController.searchResultsController).tableView
.frame;
tableViewFrame.origin.y = tableViewFrame.origin.y + 64; //status bar (20) + nav bar (44)
tableViewFrame.size.height = tableViewFrame.size.height;
_searchTableViewRect = tableViewFrame;
}
[((UITableViewController *)aSearchController.searchResultsController).tableView setFrame:_searchTableViewRect];
}
#pragma mark -
#pragma mark UISearchDisplayDelegate
- (void)handleSearchForSearchString:(NSString *)searchString {
searchQuery.location = self.mapView.userLocation.coordinate;
searchQuery.input = searchString;
[searchQuery fetchPlaces:^(NSArray *places, NSError *error) {
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Could not fetch Places"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alert show];
} else {
searchResultPlaces = places;
// [self.searchController.searchResultsTableView reloadData];
[[(UITableViewController *)self.searchController.searchResultsController tableView] reloadData];
}
}];
}
- (BOOL)searchController:(UISearchController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self handleSearchForSearchString:searchString];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (![searchBar isFirstResponder]) {
// User tapped the 'clear' button.
shouldBeginEditing = NO;
[self.searchController setActive:NO];
[self.mapView removeAnnotation:selectedPlaceAnnotation];
}
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
if (shouldBeginEditing) {
// Animate in the table view.
NSTimeInterval animationDuration = 0.3;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
// self.searchController.searchResultsTableView.alpha = 0.75;
[(UITableViewController *)self.searchController.searchResultsController tableView].alpha = 0.75;
[UIView commitAnimations];
[self.searchController.searchBar setShowsCancelButton:YES animated:YES];
}
BOOL boolToReturn = shouldBeginEditing;
shouldBeginEditing = YES;
return boolToReturn;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [searchResultPlaces count];
}
- (SPGooglePlacesAutocompletePlace *)placeAtIndexPath:(NSIndexPath *)indexPath {
return searchResultPlaces[indexPath.row];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"SPGooglePlacesAutocompleteCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:#"GillSans" size:16.0];
cell.textLabel.text = [self placeAtIndexPath:indexPath].name;
return cell;
}
#pragma mark -
#pragma mark UITableViewDelegate
- (void)recenterMapToPlacemark:(CLPlacemark *)placemark {
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.02;
span.longitudeDelta = 0.02;
region.span = span;
region.center = placemark.location.coordinate;
[self.mapView setRegion:region];
}
- (void)addPlacemarkAnnotationToMap:(CLPlacemark *)placemark addressString:(NSString *)address {
[self.mapView removeAnnotation:selectedPlaceAnnotation];
selectedPlaceAnnotation = [[MKPointAnnotation alloc] init];
selectedPlaceAnnotation.coordinate = placemark.location.coordinate;
selectedPlaceAnnotation.title = address;
[self.mapView addAnnotation:selectedPlaceAnnotation];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SPGooglePlacesAutocompletePlace *place = [self placeAtIndexPath:indexPath];
[place resolveToPlacemark:^(CLPlacemark *placemark, NSString *addressString, NSError *error) {
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Could not map selected Place"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alert show];
} else if (placemark) {
[self addPlacemarkAnnotationToMap:placemark addressString:addressString];
[self recenterMapToPlacemark:placemark];
[self requestForwardGeoCoding:[self placeAtIndexPath:indexPath].name];
// ref: https://github.com/chenyuan/SPGooglePlacesAutocomplete/issues/10
[self.searchController setActive:NO];
// [self.searchController.searchResultsTableView deselectRowAtIndexPath:indexPath animated:NO];
}
}];
}
#end
You need to implement the UISearchResultsUpdating protocol.
#interface MainViewController : UIViewController <..., UISearchResultsUpdating>
.
.
.
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
// Filter results and reload table data
}
-(void) setupSearchController {
.
.
.
_searchController.searchResultsUpdater = self;
}
(as an aside, putting Google place results onto an Apple map is a violation of Google's terms of use, I believe).
i am newbie in iOS Development i want to Show multiple Annotation in MKMapViewController in iOS for that i write a code as in my viewDidLoad method
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate=self;
NSArray *name=[[NSArray alloc]initWithObjects:
#"VelaCherry",
#"Perungudi",
#"Tharamani", nil];
self.annotation=[[NSMutableArray alloc]initWithCapacity:[name count]];
MKPointAnnotation *mappin=[[MKPointAnnotation alloc]init];
CLLocationCoordinate2D location;
location.latitude=(double)12.970760345459;
location.longitude=(double)80.2190093994141;
mappin.coordinate=location;
mappin.title=[name objectAtIndex:0];
[self.annotation addObject:mappin];
location.latitude=(double)12.9752297537231;
location.longitude=(double)80.2313079833984;
mappin.coordinate=location;
mappin.title=[name objectAtIndex:1];
[self.annotation addObject:mappin];
location.latitude=(double)12.9788103103638;
location.longitude=(double)80.2412414550781;
mappin.title=[name objectAtIndex:2];
[self.annotation addObject:mappin];
[self.mapView addAnnotations:self.annotation];
self.mapView.mapType = MKMapTypeStandard;
self.mapView.showsUserLocation = YES;
}
But it is not show any of annotation in MKMapViewController please give me Solution for this.
I've written a demo app here which shows you one way to make your code a bit more cleaner and reusable, taking into account Paulw11's sugggestion.
Note, this method is purely done with code, no interface builder.
ViewController.h
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController <MKMapViewDelegate>
#property (nonatomic, strong) MKMapView *mapView;
#end
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
[self addAllPins];
}
-(void)initViews
{
self.mapView = [[MKMapView alloc] init];
self.mapView.delegate = self;
self.mapView.showsUserLocation = YES;
MKCoordinateRegion region = self.mapView.region;
region.center = CLLocationCoordinate2DMake(12.9752297537231, 80.2313079833984);
region.span.longitudeDelta /= 1.0; // Bigger the value, closer the map view
region.span.latitudeDelta /= 1.0;
[self.mapView setRegion:region animated:NO]; // Choose if you want animate or not
[self.view addSubview:self.mapView];
}
-(void)initConstraints
{
self.mapView.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"mapView": self.mapView
};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[mapView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[mapView]|" options:0 metrics:nil views:views]];
}
-(void)addAllPins
{
self.mapView.delegate=self;
NSArray *name=[[NSArray alloc]initWithObjects:
#"VelaCherry",
#"Perungudi",
#"Tharamani", nil];
NSMutableArray *arrCoordinateStr = [[NSMutableArray alloc] initWithCapacity:name.count];
[arrCoordinateStr addObject:#"12.970760345459, 80.2190093994141"];
[arrCoordinateStr addObject:#"12.9752297537231, 80.2313079833984"];
[arrCoordinateStr addObject:#"12.9788103103638, 80.2412414550781"];
for(int i = 0; i < name.count; i++)
{
[self addPinWithTitle:name[i] AndCoordinate:arrCoordinateStr[i]];
}
}
-(void)addPinWithTitle:(NSString *)title AndCoordinate:(NSString *)strCoordinate
{
MKPointAnnotation *mapPin = [[MKPointAnnotation alloc] init];
// clear out any white space
strCoordinate = [strCoordinate stringByReplacingOccurrencesOfString:#" " withString:#""];
// convert string into actual latitude and longitude values
NSArray *components = [strCoordinate componentsSeparatedByString:#","];
double latitude = [components[0] doubleValue];
double longitude = [components[1] doubleValue];
// setup the map pin with all data and add to map view
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);
mapPin.title = title;
mapPin.coordinate = coordinate;
[self.mapView addAnnotation:mapPin];
}
If you zoom out a little, you'll see all three pins:
You should use the function CLLocationCoordinate2DMake to initialise your location objects in a single line. More importantly you need to allocate a new annotation object for each annotation -
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate=self;
NSArray *name=[[NSArray alloc]initWithObjects:
#"VelaCherry",
#"Perungudi",
#"Tharamani", nil];
self.annotation=[[NSMutableArray alloc]initWithCapacity:[name count]];
MKPointAnnotation *mappin;
CLLocationCoordinate2D location;
location = CLLocationCoordinate2DMake(12.970760345459,80.2190093994141);
mappin = [[MKPointAnnotation alloc]init];
mappin.coordinate=location;
mappin.title=[name objectAtIndex:0];
[self.annotation addObject:mappin];
mappin = [[MKPointAnnotation alloc]init];
location = CLLocationCoordinate2DMake(12.9752297537231,80.2313079833984);
mappin.coordinate=location;
mappin.title=[name objectAtIndex:1];
[self.annotation addObject:mappin];
mappin = [[MKPointAnnotation alloc]init];
location = CLLocationCoordinate2DMake(12.9788103103638,80.2412414550781);
mappin.coordinate=location;
mappin.title=[name objectAtIndex:2];
[self.annotation addObject:mappin];
[self.mapView addAnnotations:self.annotation];
self.mapView.mapType = MKMapTypeStandard;
self.mapView.showsUserLocation = YES;
}
//
// MyAnnotation.h
// SimpleMapView
//
// Created by Mayur Birari.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString* title;
NSString* subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
#end
//
// MyAnnotation.m
// SimpleMapView
//
// Created by Mayur Birari .
//
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize title;
#synthesize subtitle;
#synthesize coordinate;
- (void)dealloc
{
[super dealloc];
self.title = nil;
self.subtitle = nil;
}
#end
//
// RootViewController.h
// SimpleMapView
//
// Created by Mayur Birari.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "UserProfileVC.h"
#interface RootViewController : UIViewController<MKMapViewDelegate> {
IBOutlet MKMapView* mapView;
IBOutlet UserProfileVC* userProfileVC;
}
#property(nonatomic,retain) IBOutlet MKMapView* mapView;
#property(nonatomic,retain) IBOutlet UserProfileVC* userProfileVC;
#end
//
// RootViewController.m
// SimpleMapView
//
// Created by Mayur Birari.
//
#import "RootViewController.h"
#import "MyAnnotation.h"
#import "UserProfileVC.h"
#implementation RootViewController
#synthesize mapView,userProfileVC;
#pragma mark -
#pragma mark View lifecycle
- (void)gotoLocation
{
// start off by default in San Francisco
MKCoordinateRegion newRegion;
newRegion.center.latitude = 37.786996;
newRegion.center.longitude = -122.440100;
newRegion.span.latitudeDelta = 0.112872;
newRegion.span.longitudeDelta = 0.109863;
[self.mapView setRegion:newRegion animated:YES];
}
- (void)viewDidLoad {
[super viewDidLoad];
CLLocation *userLoc = mapView.userLocation.location;
CLLocationCoordinate2D userCoordinate = userLoc.coordinate;
NSLog(#"user latitude = %f",userCoordinate.latitude);
NSLog(#"user longitude = %f",userCoordinate.longitude);
mapView.delegate=self;
NSMutableArray* annotations=[[NSMutableArray alloc] init];
CLLocationCoordinate2D theCoordinate1;
theCoordinate1.latitude = 37.786996;
theCoordinate1.longitude = -122.419281;
CLLocationCoordinate2D theCoordinate2;
theCoordinate2.latitude = 37.810000;
theCoordinate2.longitude = -122.477989;
CLLocationCoordinate2D theCoordinate3;
theCoordinate3.latitude = 37.760000;
theCoordinate3.longitude = -122.447989;
CLLocationCoordinate2D theCoordinate4;
theCoordinate4.latitude = 37.80000;
theCoordinate4.longitude = -122.407989;
MyAnnotation* myAnnotation1=[[MyAnnotation alloc] init];
myAnnotation1.coordinate=theCoordinate1;
myAnnotation1.title=#"Rohan";
myAnnotation1.subtitle=#"in the city";
MyAnnotation* myAnnotation2=[[MyAnnotation alloc] init];
myAnnotation2.coordinate=theCoordinate2;
myAnnotation2.title=#"Vaibhav";
myAnnotation2.subtitle=#"on a Bridge";
MyAnnotation* myAnnotation3=[[MyAnnotation alloc] init];
myAnnotation3.coordinate=theCoordinate3;
myAnnotation3.title=#"Rituraaj";
myAnnotation3.subtitle=#"in the forest";
MyAnnotation* myAnnotation4=[[MyAnnotation alloc] init];
myAnnotation4.coordinate=theCoordinate4;
myAnnotation4.title=#"Amit";
myAnnotation4.subtitle=#"at Russian Hill";
[mapView addAnnotation:myAnnotation1];
[mapView addAnnotation:myAnnotation2];
[mapView addAnnotation:myAnnotation3];
[mapView addAnnotation:myAnnotation4];
[annotations addObject:myAnnotation1];
[annotations addObject:myAnnotation2];
[annotations addObject:myAnnotation3];
[annotations addObject:myAnnotation4];
NSLog(#"%d",[annotations count]);
//[self gotoLocation];//to catch perticular area on screen
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
// Walk the list of overlays and annotations and create a MKMapRect that
// bounds all of them and store it into flyTo.
MKMapRect flyTo = MKMapRectNull;
for (id <MKAnnotation> annotation in annotations) {
NSLog(#"fly to on");
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
if (MKMapRectIsNull(flyTo)) {
flyTo = pointRect;
} else {
flyTo = MKMapRectUnion(flyTo, pointRect);
//NSLog(#"else-%#",annotationPoint.x);
}
}
// Position the map so that all overlays and annotations are visible on screen.
mapView.visibleMapRect = flyTo;
UIBarButtonItem* temp=[[UIBarButtonItem alloc] init];
temp.title=#"Back";
self.navigationItem.backBarButtonItem=temp;
[temp release];
}
/*
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
*/
/*
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
*/
/*
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
*/
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait || UIInterfaceOrientationLandscapeLeft || UIInterfaceOrientationLandscapeRight);
}
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 0;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
#pragma mark MKMapViewDelegate
/*
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
return [kml viewForOverlay:overlay];
}
*/
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"welcome into the map view annotation");
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// try to dequeue an existing pin view first
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor=MKPinAnnotationColorPurple;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
UIImageView *profileIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"profile.png"]];
pinView.leftCalloutAccessoryView = profileIconView;
[profileIconView release];
return pinView;
}
-(IBAction)showDetails:(id)sender{
NSLog(#"Annotation Click");
self.userProfileVC.title=((UIButton*)sender).currentTitle;
[self.navigationController pushViewController:self.userProfileVC animated:YES];
}
- (void)dealloc {
[super dealloc];
}
#end
I'm trying to use MapBox's MBXMapKit to add a custom style to my map. I've followed the sample app and the docs but I keep seeing the standard MapKit UI.
Am I missing something glaringly obvious here? I've added the protocol methods from the SampleApp # MBXMapBox GitHub, and added a MBXRasterTileOverlay as I should... So I'm not really sure what's missing.
//
// MapViewController.h
//
#import <UIKit/UIKit.h>
#import "MapKit/MapKit.h"
#import "MBXMapKit.h"
#interface MapViewController : UIViewController <MKMapViewDelegate, MBXRasterTileOverlayDelegate>
#end
|
//
// MapViewController.m
//
#import "MapViewController.h"
#interface MapViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
#implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setUpNavigationBarView];
MBXRasterTileOverlay *blah = [[MBXRasterTileOverlay alloc] initWithMapID:#"sparkyrobinson.jp6f81f2" includeMetadata:YES includeMarkers:YES];
MBXRasterTileOverlay *rasterOverlay = [[MBXRasterTileOverlay alloc] initWithMapID:#"sparkyrobinson.jp6f81f2"];
rasterOverlay.delegate = self;
[self.mapView addOverlay:blah];
}
- (void) setUpNavigationBarView
{
UINavigationBar *navigationBar = self.navigationController.navigationBar;
[navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
navigationBar.shadowImage = [UIImage new];
navigationBar.translucent = YES;
navigationBar.titleTextAttributes = #{
NSForegroundColorAttributeName: UIColorFromRGB(TURQUOISE),
};
}
#pragma mark - MKMapViewDelegate protocol implementation
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
// This is boilerplate code to connect tile overlay layers with suitable renderers
//
if ([overlay isKindOfClass:[MBXRasterTileOverlay class]])
{
MKTileOverlayRenderer *renderer = [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
return renderer;
}
return nil;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// This is boilerplate code to connect annotations with suitable views
//
if ([annotation isKindOfClass:[MBXPointAnnotation class]])
{
static NSString *MBXSimpleStyleReuseIdentifier = #"MBXSimpleStyleReuseIdentifier";
MKAnnotationView *view = [mapView dequeueReusableAnnotationViewWithIdentifier:MBXSimpleStyleReuseIdentifier];
if (!view)
{
view = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MBXSimpleStyleReuseIdentifier];
}
view.image = ((MBXPointAnnotation *)annotation).image;
view.canShowCallout = YES;
return view;
}
return nil;
}
#pragma mark - MBXRasterTileOverlayDelegate implementation
- (void)tileOverlay:(MBXRasterTileOverlay *)overlay didLoadMetadata:(NSDictionary *)metadata withError:(NSError *)error
{
// This delegate callback is for centering the map once the map metadata has been loaded
//
if (error)
{
NSLog(#"Failed to load metadata for map ID %# - (%#)", overlay.mapID, error?error:#"");
}
else
{
[self.mapView mbx_setCenterCoordinate:overlay.center zoomLevel:overlay.centerZoom animated:NO];
}
}
- (void)tileOverlay:(MBXRasterTileOverlay *)overlay didLoadMarkers:(NSArray *)markers withError:(NSError *)error
{
// This delegate callback is for adding map markers to an MKMapView once all the markers for the tile overlay have loaded
//
if (error)
{
NSLog(#"Failed to load markers for map ID %# - (%#)", overlay.mapID, error?error:#"");
}
else
{
[self.mapView addAnnotations:markers];
}
}
- (void)tileOverlayDidFinishLoadingMetadataAndMarkers:(MBXRasterTileOverlay *)overlay
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
#end
Cheers.
Everything looks good. Are you sure that the self.mapView outlet is hooked up and you're not adding an overlay to nil?