Open Detail View from Annotation - ios

I have a map view with several annotations. Each annotation has a button that takes the user to a detail view for that annotation. The detail view currently has two labels, one for the title from the annotation and the other for the subtitle of the annotation, and a "Get Directions" button. I want the title label to be populated with the title from the annotation and the subtitle label to be populated with the subtitle from the annotation. I want the Get Directions button to take the user into the Maps app and give them directions to the address from their current location. I'd also like to add website and phone number to the detail view but I'm not sure how to populate those fields either. The detail view is called AnnotationDetailView but I haven't done anything with it besides add the button and labels in IB. I'm just not sure how to populate the labels and get the button doing what I want. Any help would be great.
Here is my code:
//
// RSFM.m
#import "RSFM.h"
#import "AnnotationDetailView.h"
#interface RSFM ()
#end
#implementation RSFM
{
}
#synthesize centerCoordinate, coordinate, title, subtitle;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.title = NSLocalizedString(#"Farm Markets", #"Farm Markets");
// Create location manager object
locationManager = [[CLLocationManager alloc]init];
[locationManager setDelegate:self];
// And we want it to be as accurate as possible regardless of how much time/power it takes
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
// Tell our manager to start looking for its location immediately
// [locationManager startUpdatingLocation];
}
return self;
}
/*
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
{
centerCoordinate = CLLocationCoordinate2DMake(37.7885, 85.3279);
}
*/
- (void)findLocation
{
[locationManager startUpdatingLocation];
[activityIndicator startAnimating];
// [locationTitleField setHidden:YES];
[locationManager stopUpdatingLocation];
}
- (void)foundLocation:(CLLocation *)loc
{
CLLocationCoordinate2D coord = [loc coordinate];
// Create an instance of BNRMapPoint with the current data
// BNRMapPoint *mp = [[BNRMapPoint alloc]initWithCoordinate:coord title:[locationTitleField text]];
// Add it to the map view
// [worldView addAnnotation:mp];
// Zoom the region to this location
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 700000, 700000);
[worldView setRegion:region animated:YES];
// Reset the UI
// [locationTitleField setText:#""];
[activityIndicator stopAnimating];
// [locationTitleField setHidden:NO];
[locationManager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%#", newLocation);
// How many seconds ago was this new location created?
NSTimeInterval t = [[newLocation timestamp]timeIntervalSinceNow];
// CLLocationManagers will return the last found location of the device first, you don't want that data in this case.
// If this location was made more than 3 minutes ago, ignore it.
if (t < -180)
{
// this is cached data, you don't want it, keep looking
return;
}
[self foundLocation:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"Could not find location: %#", error);
}
- (void)dealloc
{
// Tell the location manager to stop sending us messages
[locationManager setDelegate:nil];
}
- (IBAction)showDetails:(id)sender
{
AnnotationDetailView *detail = [[AnnotationDetailView alloc] initWithNibName:nil bundle:nil];
detail.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self.navigationController pushViewController:detail animated:YES];
}
- (MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// If it's the user location, 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];
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
return pinView;
}
- (void)viewDidLoad
{
[locationManager startUpdatingLocation];
[worldView setShowsUserLocation:YES];
[locationManager stopUpdatingLocation];
NSMutableArray *marketLocations = [[NSMutableArray alloc]init];
NSMutableArray *lat = [[NSMutableArray alloc]initWithObjects:#"37.7867266", #"37.0703517", #"37.1610806", #"37.318367", #"37.3559204", #"37.4154066", #"37.4757622", #"37.7450252", #"37.6318978", #"37.0716803", nil];
NSMutableArray *lon = [[NSMutableArray alloc]initWithObjects:#"-87.608209", #"-88.1237899", #"-87.9148629", #"-87.5074402", #"-87.5448032", #"-87.8003148", #"-87.9515986", #"-87.9061638", #"-87.1148574", #"-87.3008418", nil];
NSMutableArray *title1 = [[NSMutableArray alloc]initWithObjects:#"Cates Farm", #"Broadbent B & B Foods", #"Cayce's Pumpkin Patch", #"Metcalfe Landscaping", #"Brumfield Farm Market", #"Dogwood Valley Farm", #"Country Fresh Meats & Farmers Market", #"Jim David Meats", #"Trunnell's Farm Market", #"Lovell's Orchard & Farm Market", nil];
NSMutableArray *subtitle1 = [[NSMutableArray alloc]initWithObjects:#"Hwy 425 Henderson, KY 42420", #"257 Mary Blue Road Kuttawa, KY 42055", #"153 Farmersville Road Princeton, KY 42445", #"410 Princeton Road Madisonville, KY 42431", #"3320 Nebo Road Madisonville, KY 42431", #"4551 State Route 109N Clay, KY 42404", #"9355 US Hwy 60 W Sturgis, KY 42459",#"350 T. Frank Wathen Rd. Uniontown, KY 42461", #"9255 Hwy 431 Utica, KY 42376", #"22850 Coal Creek Road Hopkinsville, KY 42240", nil];
CLLocationCoordinate2D location;
MKPointAnnotation *marketAnnotation;
for (int x = 0; x < [lat count]; x++)
{
marketAnnotation = [[MKPointAnnotation alloc]init];
location.latitude = [[lat objectAtIndex:x]floatValue];
location.longitude = [[lon objectAtIndex:x]floatValue];
marketAnnotation.coordinate = location;
marketAnnotation.title = [title1 objectAtIndex:x];
marketAnnotation.subtitle = [subtitle1 objectAtIndex:x];
[marketLocations addObject:marketAnnotation];
}
[worldView addAnnotations:marketLocations];
/*
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = CLLocationCoordinate2DMake(37.7867266, -87.608209);
point.title = #"Cates Farm";
point.subtitle = #"Hwy 425 Henderson, KY 42420";
[worldView addAnnotation:point];
*/
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D loc = [userLocation coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 700000, 700000);
[worldView setRegion:region animated:YES];
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
}
- (IBAction)selectSegmentControl
{
int segmentTouched = [mapVarieties selectedSegmentIndex];
NSString *segmentName = [mapVarieties titleForSegmentAtIndex:segmentTouched];
if ([segmentName isEqualToString:#"Street"])
{
[worldView setMapType:MKMapTypeStandard];
}
if ([segmentName isEqualToString:#"Satellite"])
{
[worldView setMapType:MKMapTypeSatellite];
}
if ([segmentName isEqualToString:#"Hybrid"])
{
[worldView setMapType:MKMapTypeHybrid];
}
}
#end
Here is where I show the detail view
- (IBAction)showDetails:(id)sender
{
AnnotationDetailView *detail = [[AnnotationDetailView alloc] initWithNibName:nil bundle:nil];
detail.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
NSLog(#"%#", marketAnnotation.title);
detail.ti.text = marketAnnotation.title;
[self.navigationController pushViewController:detail animated:YES];
}
and the AnnotationDetailView
//
// AnnotationDetailView.m
#import "AnnotationDetailView.h"
#interface AnnotationDetailView ()
#end
#implementation AnnotationDetailView
#synthesize ti;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// [title setText:marketAnnotation.title];
// [subtitle setText:marketAnnotation.subtitle];
ti = [[UILabel alloc]initWithFrame:CGRectMake(20, 20, 281, 21)];
[self.view addSubview:ti];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I'm having a couple of issues with this. One, the label is not showing up. Two, I have an NSLog statement in my showDetails method to show me what marketAnnotations is. It is showing the title of the last annotation added.

You can add extra parameters to your MKAnnotation class. For example this Annotation class uses 3 extra strings to hold information:
// MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation>
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy, readonly) NSString *title;
#property (nonatomic, copy, readonly) NSString *subtitle;
#property (nonatomic, copy, readonly) NSString *myString1;
#property (nonatomic, copy, readonly) NSString *myString2;
#property (nonatomic, copy, readonly) NSString *myString3;
-(id)initWithCoordinates:(CLLocationCoordinate2D) paramCoordinates
title:(NSString *) paramTitle
subTitle:(NSString *) paramSubTitle
myString1:(NSString *) paramMyString1
myString2:(NSString *) paramMyString2
myString3:(NSString *) paramMyString3;
#end
// MyAnnotation.m
#import "MyAnnotation.h"
#implementation MyAnnotation
-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
title:(NSString *)paramTitle
subTitle:(NSString *)paramSubTitle
myString1:(NSString *)paramMyString1
myString2:(NSString *)paramMyString2
myString3:(NSString *)paramMyString1
{
self = [super init];
if(self != nil)
{
_coordinate = paramCoordinates;
_title = paramTitle;
_subtitle = paramSubTitle;
_myString1 = paramMyString1;
_myString2 = paramMyString2;
_myString3 = paramMyString3;
}
return (self);
}
#end
When the user taps a pin, you can do this to pass information from the Annotation to the next View Controller:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
if ([(UIButton*)control buttonType] == UIButtonTypeDetailDisclosure)
{
YourViewController *vc = [[YourViewController alloc] init];
[vc setTitleString:[(MyAnnotation *)view.annotation title]];
[vc setSubTitleString:[(MyAnnotation *)view.annotation subTitle]];
[vc setPassedString1:[(MyAnnotation *)view.annotation myString1]];
[vc setPassedString2:[(MyAnnotation *)view.annotation myString2]];
[vc setPassedString3:[(MyAnnotation *)view.annotation myString3]];
[[self navigationController] pushViewController:vc animated:YES];
}
}
In your next View Controller (vc), you can modify the button text like this:
[myButton setTitle:myPassedString1 forState:UIControlStateNormal];

Related

How to locate my current location in iOS?

i got this error what that error meant to be.i can't understand what error it is.
so plz help
thanks
error
1.ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mycurrentlocation;
#end
2. ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController #synthesize mycurrentlocation;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mycurrentlocation.delegate = self; }
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated. }
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion re = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800,
800);
[self.mycurrentlocation setRegion:[self.mycurrentlocation regionThatFits:re] animated:YES];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = userLocation.coordinate;
point.title = #"Where am I?";
point.subtitle = #"I'm here!!!";
[self.mycurrentlocation addAnnotation:point]; }
#end
Then put this line of code in the viewDidLoad method of your class:
[self.locationManager requestAlwaysAuthorization];
You need to add the core location framework and Map Kit framework.
In your AppName-Info.plist Add a new row with the key name being:
NSLocationWhenInUseUsageDescription
Or
NSLocationAlwaysUsageDescription
With the value being a string of the message that you want to be displayed:
YourAppName would like to use your location.
In your header file. (I use App Name-Prefix.pch but YourViewController.h will work too)
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
YourViewController.h
#import <MapKit/MapKit.h>
#import <MapKit/MKAnnotation.h>
#interface YourViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate> {
}
#property(nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic, retain) CLLocationManager *locationManager;
YourViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
mapView.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
// Use one or the other, not both. Depending on what you put in info.plist
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
mapView.showsUserLocation = YES;
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
NSLog(#"%#", [self deviceLocation]);
//View Area
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceLat {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.latitude];
}
- (NSString *)deviceLon {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceAlt {
return [NSString stringWithFormat:#"%f", self.locationManager.location.altitude];
}

Select Statement Parse Objective C

I have just begun development with 'objective candParse`.
I have a function in my app where I am allowing the user to enter in a new climb.
Data are stored in a table of mine in Parse. I add that climb into the map view portion of my app.
I am wanting to write a select statement that stores all of the results from the query into an array of some sort and then I will dump that into the map view portion. This way I am thinking that it will dynamically add a map pin to the map every time a new area is added, if it does not already exist of course.
I am a .net developer and in this scenario I would grab all the data and then dump it into a data table and real with it from there.... But I am not sure of the best practice on doing this with my above scenario in objective c.
I will post my code for the map below :
MapPin.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapPin : NSObject <MKAnnotation>
{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
MapPin.m
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate, title, subtitle;
#end
MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController
{
MKMapView *mapView;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
-(IBAction)SetMap:(id)sender;
-(IBAction)GetLocation:(id)sender;
-(IBAction)Directions:(id)sender;
#end
MapViewController.m
#import "MapViewController.h"
#import "MapPin.h"
#interface MapViewController ()<MKMapViewDelegate>
#end
#implementation MapViewController
#synthesize mapView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
mapView.delegate = self;
//new
//[self.mapView setShowsUserLocation:YES];
//Moss Preserve annotation and map pin
MapPin *MossPreserveAnnotation = [[MapPin alloc] init];
MossPreserveAnnotation.title = #"Moss Rock Preserve Boulder Fields";
MossPreserveAnnotation.subtitle = #"Hoover, AL";
MossPreserveAnnotation.coordinate = CLLocationCoordinate2DMake(33.3816566, -86.8415451);
[mapView addAnnotation:MossPreserveAnnotation];
//Setup map
MKCoordinateRegion mapCoordRegion;
mapCoordRegion.center.latitude = 39;
mapCoordRegion.center.longitude = -97;
mapCoordRegion.span.latitudeDelta = 60.0;
mapCoordRegion.span.longitudeDelta = 60.0;
[mapView setRegion:mapCoordRegion];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
self.navigationController.navigationBar.hidden = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
// Create an MKMapItem to pass to the Maps app
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:view.annotation.coordinate
addressDictionary:nil];
MKMapItem *MapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[MapItem setName:view.annotation.title];
NSDictionary *launchOptions = #{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};
// Get the "Current User Location" MKMapItem
MKMapItem *currentLocationItem = [MKMapItem mapItemForCurrentLocation];
[MKMapItem openMapsWithItems:#[currentLocationItem, MapItem]
launchOptions:launchOptions];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"MKPinAnnotationView"];
annotationView.canShowCallout = YES;
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[detailButton setTintColor:[UIColor colorWithRed:183/255.0 green:207/255.0 blue:85/255.0 alpha:0.5]];
annotationView.rightCalloutAccessoryView = detailButton;
return annotationView;
}
-(IBAction)SetMap:(id)sender;
{
switch (((UISegmentedControl *) sender).selectedSegmentIndex)
{
case 0:
mapView.mapType = MKMapTypeStandard;
break;
case 1:
mapView.mapType = MKMapTypeSatellite;
break;
case 2:
mapView.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
-(IBAction)GetLocation:(id)sender;
{
mapView.showsUserLocation = YES;
}
-(IBAction)Directions:(id)sender;
{
NSString *urlString = #"http://maps.apple.com/maps?daddr=33.3816566,-86.8415451";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}
#end
Sorry to dump a lot of code in here... Just wanted to provide everyone with what I had.
Before answering, some notes:
Start methods in lower case, it's a common practice.
A pin and an annotation are two diferent concepts, let's say a pin is the view and an annotation is the model (or business object), so it's better if you call MapPin like MapAnnontation (or just Annontation, cause Map is redundant). Probably in a close future you are going to have custom pins, that are a subclass of MKAnnotationView.
For your reply, I have an app that retrieves places for the current map area from Parse (www.sharewifiapp.com). This is the code and below some explanations:
#pragma mark MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
[self.hotspotsQuery cancel];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
//DDDebugLog(#"zoom %lu", (unsigned long)[self.mapView zoomLevel]);
// retrieve all hotspots using the filtering and the current view port
self.hotspotsQuery = [PFQuery queryWithClassName:[SWHotspot parseClassName]];
MKMapRect mRect = self.mapView.visibleMapRect;
MKMapPoint neMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), mRect.origin.y);
MKMapPoint swMapPoint = MKMapPointMake(mRect.origin.x, MKMapRectGetMaxY(mRect));
CLLocationCoordinate2D neCoord = MKCoordinateForMapPoint(neMapPoint);
CLLocationCoordinate2D swCoord = MKCoordinateForMapPoint(swMapPoint);
PFGeoPoint* swGeoPoint=[PFGeoPoint geoPointWithLatitude:swCoord.latitude longitude:swCoord.longitude];
PFGeoPoint* neGeoPoint=[PFGeoPoint geoPointWithLatitude:neCoord.latitude longitude:neCoord.longitude];
[self.hotspotsQuery whereKey:#"location" withinGeoBoxFromSouthwest:swGeoPoint toNortheast:neGeoPoint];
[self.hotspotsQuery includeKey:#"owner"];
[self.hotspotsQuery orderByDescending:#"updatedAt"];
self.hotspotsQuery.limit=1000;
self.loadingHotspotsActivityView.hidden=NO;
[self.hotspotsQuery findObjectsInBackgroundWithBlock:^(NSArray *hotspots, NSError *error) {
self.loadingHotspotsActivityView.hidden=YES;
if (error) {
DDLogError(#"Error retrieving hotspots: %#", [error userInfo][#"error"]);
} else {
// TEST.
/*
NSLog(#"retrieved: %lu", (unsigned long)objects.count);
[self.mapView removeAnnotations:self.mapView.annotations];
[self.mapView addAnnotations:objects];
*/
// remove hotspots that are not in the current response (hotstpots)
NSMutableArray* hotspotsToRemove=[self.mapView.annotations mutableCopy];
[hotspotsToRemove removeObjectsInArray:hotspots];
[self.mapView removeAnnotations:hotspotsToRemove];
// add hotpots from the current response that were not in the original set
NSMutableArray* hotspotsToAdd=[hotspots mutableCopy];
[hotspotsToAdd removeObjectsInArray:self.mapView.annotations];
[self.mapView addAnnotations:hotspotsToAdd];
}
}];
}
Important points:
-Save your parse query so you can cancel it.
-Cancel it when user starts moving the map, and launch a new request when user stops moving the map.
-Every time you receive new places from parse query, you can remove all annotations and put the new ones, but from a performance point of view that's not nice. If you want that try my code where it says TEST.
-If you want to improve performance, follow my logic, that removes annotations that are not in the current reply and only add new places if they are not in the map.
Hope this helps.

About the Tab bar button with NSMutableArray annotation in MapKit

I have created 4 type of annotation group. In the map UI, I also added a tab bar on the bottom as my button.
My tab bar is used to filter out the annotation in MapKit.
For example... I have 4 group of annotation and 4 tab bar item.
When I clicked tab bar item 1, it show only 1 group of annotation in MapKit, other group of annotation will hide/remove in MapKit but I failed to achieve this kind of work.
My code:
in MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface MapViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate , UITabBarDelegate>{
IBOutlet UITabBar *tabBar;
}
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
my mapViewController.m:
#import "MapViewController.h"
#import "SWRevealViewController.h"
#import "Annotation.h"
#interface MapViewController ()<CLLocationManagerDelegate>
#end
//set desitination of map
#define PENANG_LATI 5.419501;
#define PENANG_LONG 100.323264;
//shop
#define SHOP_LATI 5.419501;
#define SHOP_LONG 100.323264;
//cafe
#define CAFE_LATI 5.419917;
#define CAFE_LONG 100.322969;
//food
#define FOOD_LATI 5.419746;
#define FOOD_LONG 100.322610;
//mural
#define MURAL_LATI 5.419786;
#define MURAL_LONG 100.322510;
#define THE_SPAN 0.005f;
#implementation MapViewController
#synthesize mapView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//tabBar
tabBar.delegate = self;
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude = PENANG_LATI;
center.longitude = PENANG_LONG;
//SPAN
MKCoordinateSpan span;
span.latitudeDelta = THE_SPAN;
span.longitudeDelta = THE_SPAN;
myRegion.center = center;
myRegion.span = span;
//set map
[mapView setRegion:myRegion animated:YES];
SWRevealViewController *revealViewController = self.revealViewController;
if ( revealViewController )
{
[self.sidebarButton setTarget: self.revealViewController];
[self.sidebarButton setAction: #selector( revealToggle: )];
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
/*
//create coordinate
CLLocationCoordinate2D penangLocation;
penangLocation.latitude = PENANG_LATI;
penangLocation.longitude = PENANG_LONG;
Annotation * myAnnotation = [Annotation alloc];
myAnnotation.coordinate = penangLocation;
myAnnotation.title = #"THE ONE ACADEMY PENANG";
myAnnotation.subtitle = #"HELLO!! I STUDY HERE";
[self.mapView addAnnotation:myAnnotation];
*/
}
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
//my group of annotation location
NSMutableArray * myShop = [[NSMutableArray alloc] init];
NSMutableArray * myCafe = [[NSMutableArray alloc] init];
NSMutableArray * myFood = [[NSMutableArray alloc] init];
NSMutableArray * myMural = [[NSMutableArray alloc] init];
CLLocationCoordinate2D penangLocation;
Annotation * myShopAnnotation;
Annotation * myCafeAnnotation;
Annotation * myFoodAnnotation;
Annotation * myMuralAnnotation;
//shop location
myShopAnnotation = [[Annotation alloc] init];
penangLocation.latitude = SHOP_LATI;
penangLocation.longitude = SHOP_LONG;
myShopAnnotation.coordinate = penangLocation;
myShopAnnotation.title = #"Shop";
myShopAnnotation.subtitle = #"I study here";
[myShop addObject:myShopAnnotation];
//cafe location
myCafeAnnotation = [[Annotation alloc] init];
penangLocation.latitude = CAFE_LATI;
penangLocation.longitude = CAFE_LONG;
myCafeAnnotation.coordinate = penangLocation;
myCafeAnnotation.title = #"Cafe";
myCafeAnnotation.subtitle = #"I paid here";
[myCafe addObject:myCafeAnnotation];
//food location
myFoodAnnotation = [[Annotation alloc] init];
penangLocation.latitude = FOOD_LATI;
penangLocation.longitude = FOOD_LONG;
myFoodAnnotation.coordinate = penangLocation;
myFoodAnnotation.title = #"Food";
myFoodAnnotation.subtitle = #"I walk here";
[myFood addObject:myFoodAnnotation];
//Mural location
myMuralAnnotation = [[Annotation alloc] init];
penangLocation.latitude = MURAL_LATI;
penangLocation.longitude = MURAL_LONG;
myMuralAnnotation.coordinate = penangLocation;
myMuralAnnotation.title = #"Mural";
myMuralAnnotation.subtitle = #"I walk here";
[myMural addObject:myMuralAnnotation];
if(item.tag == 1)
{
//show and hide annotation
NSLog(#"shop");
[mapView addAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView removeAnnotations:myMural];
}
if(item.tag == 2)
{
//show and hide annotation
NSLog(#"cafe");
[mapView removeAnnotations:myShop];
[mapView addAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView removeAnnotations:myMural];
}
if(item.tag == 3)
{
//show and hide annotation
NSLog(#"food");
[mapView removeAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView addAnnotations:myMural];
}
if(item.tag == 4)
{
//show and hide annotation
NSLog(#"mural");
[mapView removeAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView addAnnotations:myMural];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
When removeAnnotations: is called like this:
[mapView removeAnnotations:myCafe];
the map view looks for the exact objects (using pointer comparison) in myCafe that are already on the map.
The map view here does not match up annotations using their coordinate, title, etc.
Since the code creates new instances of each annotation every time a selection is made, the new instances are not found on the map and so removeAnnotations: does nothing.
Instead, in your case, you could just tell the map view to remove all existing annotations and then add the new annotations based on the current selection.
Instead of this:
[mapView addAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView removeAnnotations:myMural];
do this:
[mapView removeAnnotations:mapView.annotations]; //remove all
[mapView addAnnotations:myShop]; //then add new
The code could be simplified as well by using a switch statement and in each case, only create the annotations needed for the selection (you don't need to create all annotations every time).

Scrolling around my current position in MKMapView

Following Online tutorials I made a MKMapView working, but I have a couple of problems:
First problem: Map show my current position, but if I try to scroll that map It will automatically return to my position, so, for example, I am not able to see what streets are nearby, because map will center back to my current position.
Second problem: I'd like to implement some "pinch to zoom" as if you tap on my map it will get that tap point's longitude and latitude.
I surely messed up my code, because I mixed two tutorial in one ... trying to archive what I needed from my "app". :-)
This is in my .h:
#interface mappa2 : UIViewController <CLLocationManagerDelegate> {
MKMapView *mapview;
CLLocationManager *manager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapview;
And this is my messy .m
#synthesize mapview;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Procedura per TAP:
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(foundTap:)];
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
[self.mapview addGestureRecognizer:tapRecognizer];
[self startMap]; }
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Errore %#",error);
NSLog(#"Non ho potuto calcolare la posizione");
}
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"Location: %#",newLocation);
CLLocation *currentLocation = newLocation;
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] >0 ) {
placemark = [placemarks lastObject];
}
else NSLog(#"%#",error.debugDescription);
}];
MKCoordinateRegion region = { {0.0, 0.0}, {0.0, 0.0} };
region.center.latitude = currentLocation.coordinate.latitude;
region.center.longitude = currentLocation.coordinate.longitude;
region.span.longitudeDelta = 0.001f;
region.span.latitudeDelta = 0.001f;
[mapview setRegion: region animated:YES];
[mapview setScrollEnabled:YES];
}
- (void) startMap {
manager = [[CLLocationManager alloc] init];
geocoder = [[CLGeocoder alloc] init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation];
mapview.mapType = MKMapTypeStandard;
mapview.showsUserLocation = YES;
}
So .. I'd like that my map could point to my current position when "view did load", but then I'd be able to move around that point! ... and zooming in and out with gesture... is that too much for a newbie?
Thank in advance!
For the first issue, you're probably updating and resetting your location via MKMapView delegate.
Mk Mapview keeps resetting on users location?
For the second issue, the question probably contains the answer you are looking for. If not, the answers have it, plus extra code, for sure.
Get the coordinates of a point from mkmapview on iphone

How to add callout into individual annotation in map view

I'm trying to set each annotation with different callout detail info.
Currently when I click on any annotation location, it shows all the callout info.
#import "AnnotationViewController.h"
#import "Annotation.h"
#implementation AnnotationViewController
#synthesize mapView;
-(void)viewDidLoad {
[super viewDidLoad];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
[mapView setDelegate:self];
MKCoordinateRegion TT = { {0.0, 0.0} , {0.0, 0.0} };
TT.center.latitude = 43.65343;
TT.center.longitude = -79.396311;
TT.span.longitudeDelta = 0.02f;
TT.span.latitudeDelta = 0.02f;
[mapView setRegion:TT animated:YES];
Annotation *ann1 = [[Annotation alloc] init];
ann1.title = #"Annotation 01";
ann1.subtitle = #"Message 01";
ann1.coordinate = TT.center;
[mapView addAnnotation:ann1];
MKCoordinateRegion TTY = { {0.0, 0.0} , {0.0, 0.0} };
TTY.center.latitude = 43.76919;
TTY.center.longitude = -79.41245;
TTY.span.longitudeDelta = 0.02f;
TTY.span.latitudeDelta = 0.02f;
[mapView setRegion:TTY animated:YES];
Annotation *ann2 = [[Annotation alloc] init];
ann2.title = #"Annotation 02";
ann2.subtitle = #"Message 02";
ann2.coordinate = TTY.center;
[mapView addAnnotation:ann2];
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:id<MKAnnotation>)annotation
{
MKPinAnnotationView *view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"pin"];
view.pinColor = MKPinAnnotationColorPurple;
view.enabled = YES;
view.animatesDrop = YES;
view.canShowCallout = YES;
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"GPSicon.png"]];
view.leftCalloutAccessoryView = imageView;
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return view;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSString *msg = [#"Location 01" stringByAppendingFormat:#"Opening 01"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Plaza 01" message:msg delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
NSString *msg02 = [#"Location 02" stringByAppendingFormat:#"Opening 02"];
UIAlertView *alert02 = [[UIAlertView alloc] initWithTitle:#"Plaza 02" message:msg02 delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert02 show];
}
-(void)button:(id)sender {
NSLog(#"Button action");
}
- (void)dealloc
{
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
*/
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
end
So this is what's happening: When I click on "Annotation 01" the bubble will appear. But when I click on the callout "detail icon", it will popup both Location 01 & Location 2 titles.
Thanks Anna for you help. But I still get 2 callouts when i check one annotation. This is the code now..
#import "AnnotationViewController.h"
#import "Annotation.h"
#implementation AnnotationViewController
#synthesize mapView;
-(void)viewDidLoad {
[super viewDidLoad];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
[mapView setDelegate:self];
MKCoordinateRegion TT = { {0.0, 0.0} , {0.0, 0.0} };
TT.center.latitude = 43.65343;
TT.center.longitude = -79.396311;
TT.span.longitudeDelta = 0.02f;
TT.span.latitudeDelta = 0.02f;
[mapView setRegion:TT animated:YES];
Annotation *ann1 = [[Annotation alloc] init];
ann1.title = #"Annotation 01";
ann1.subtitle = #"Message 01";
ann1.coordinate = TT.center;
[mapView addAnnotation:ann1];
MKCoordinateRegion TTY = { {0.0, 0.0} , {0.0, 0.0} };
TTY.center.latitude = 43.76919;
TTY.center.longitude = -79.41245;
TTY.span.longitudeDelta = 0.02f;
TTY.span.latitudeDelta = 0.02f;
[mapView setRegion:TTY animated:YES];
Annotation *ann2 = [[Annotation alloc] init];
ann2.title = #"Annotation 02";
ann2.subtitle = #"Message 02";
ann2.coordinate = TTY.center;
[mapView addAnnotation:ann2];
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:id<MKAnnotation>)annotation
{
MKPinAnnotationView *view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"pin"];
view.pinColor = MKPinAnnotationColorPurple;
view.enabled = YES;
view.animatesDrop = YES;
view.canShowCallout = YES;
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"GPSicon.png"]];
view.leftCalloutAccessoryView = imageView;
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return view;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
//first make sure the annotation is our custom class...
if ([view.annotation isKindOfClass:[Annotation class]])
{
//cast the object to our custom class...
Annotation *ann1 = (Annotation *)view.annotation;
//show one alert view with title set to annotation's title
//and message set to annotation's subtitle...
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:ann1.title
message:ann1.subtitle
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
//first make sure the annotation is our custom class...
if ([view.annotation isKindOfClass:[Annotation class]])
{
//cast the object to our custom class...
Annotation *ann2 = (Annotation *)view.annotation;
//show one alert view with title set to annotation's title
//and message set to annotation's subtitle...
UIAlertView *alert2 = [[UIAlertView alloc]
initWithTitle:ann2.title
message:ann2.subtitle
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
-(void)button:(id)sender {
NSLog(#"Button action");
}
- (void)dealloc
{
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
*/
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
end
My Annotation.m file code
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle;
-(void)dealloc {
}
#end
My Annotation.h file code
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#end
Do i have to make alot of h/m files for each Annotation to make the callout different? im just stomp at this point. any guesses would be great, thanks!
In calloutAccessoryControlTapped, the code is showing two alert views with hard-coded text for the title and message one after the other. So that's what you get obviously.
In the calloutAccessoryControlTapped method, the annotation object whose callout button was tapped is available via view.annotation.
The view parameter is the MKAnnotationView which has an annotation property that points to its related annotation.
So change the code to show only one alert view and with the title and message based on the properties of the annotation object.
It's also a good idea to check the class of the annotation to make sure it's the type of annotation you're expecting.
For example:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
//first make sure the annotation is our custom class...
if ([view.annotation isKindOfClass:[Annotation class]])
{
//cast the object to our custom class...
Annotation *ann = (Annotation *)view.annotation;
//show one alert view with title set to annotation's title
//and message set to annotation's subtitle...
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:ann.title
message:ann.subtitle
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}

Resources