how send Core Data object from MapView to DetailView - ios

I have a list of gyms with all its properties in Core Data, I get this gyms with an NSFetchRequest and pass its to a NSArray, then with a For in and this array, I get to put the pins in the MapView, I do it with de next code (welcome suggestions for improvement this):
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
NSFetchRequest *reqInst = [NSFetchRequest fetchRequestWithEntityName:[KMTInstalacion entityName]];
reqInst.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:KMTInstalacionAttributes.tipoInstalacion_ES ascending:NO]];
KMTAppDelegate *appDelegate = (KMTAppDelegate *)[[UIApplication sharedApplication]delegate];
NSError *error;
NSArray *arrayInstalaciones = [appDelegate.model.context executeFetchRequest:reqInst error:&error];
NSLog(#"Las instalaciones encontradas en arrayInstalaciones son: %lu", (unsigned long)[arrayInstalaciones count]);
for (KMTInstalacion *todasInstalaciones in arrayInstalaciones) {
CLLocationCoordinate2D coordPunto1 = CLLocationCoordinate2DMake(todasInstalaciones.coorLatitudValue, todasInstalaciones.coorLongitudValue);
MKPointAnnotation *anotacion = [[MKPointAnnotation alloc]init];
[anotacion setCoordinate:coordPunto1];
[anotacion setTitle:todasInstalaciones.nombre_ES];
[anotacion setSubtitle:todasInstalaciones.direccion_ES];
[self.mapView addAnnotation:anotacion];
}}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"curr"];
pinView.animatesDrop = NO;
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return pinView;
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
KMTMiAnotacion *anotacion = view.annotation;
KMTDetailVC *detalle = [[KMTDetailVC allc]init];
detalle.title = anotacion.title
detalle.nombreInstalacionSeleccionada = anotacion.instalacion;
[self performSegueWithIdentifier:#"deMapa" sender:self];
}
KMTMiAnotacion.h
#interface KMTMiAnotacion : NSObject <MKAnnotation>{
NSString *title;
NSString *subTitle;
KMTInstalacion *instalacion;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subTitle;
#property (nonatomic, copy) KMTInstalacion *instalacion;
#end
When I tap on one of the pinView shows me the name and address of the gym with the button to the right.
Now what I want is when you tap on the pinView button, take you to the DetailView view and send full gym object (KMTInstalacion) corresponding pinView you've pressed, not just the title or subtitle, since each gym has about 50 properties (photos, schedules, etc ...)
Any idea how to do this?

Make a property of the gym object in your DetailViewController's .h file. Also create a custom annotation (subclass of MKAnnotation) with the same property.
#property (nonatomic, strong) KMTInstalacion *gymObj;
When setting the annotation, assign the gymObj to it's property.
Then implement this delegate method of MKMapView in your Map Controllers .m file:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
YourAnnotation *annView = view.annotation;
detailedViewOfList *detailView = [[DetailedViewOfList alloc]init];
detailView.gymObj = annotation.gymObj;
// push view modally or, however you want
}

You can use below code for sample how u can send details to other view. As per your need you to send entire object to other view...!
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
annotation *annView = view.annotation;
DetailedViewController *detailVC = [[DetailedViewController alloc] initWithNibName:#"DetailedViewController" bundle:nil];
detailVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
detailVC.address = annView.address;
detailVC.name = annView.name;
[self presentModalViewController:detailVC animated:YES];
}
Hope it helps you..

First in your annotaion view delegat make a button to go in detail view like bellow:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"current"];
mypin.pinColor = MKPinAnnotationColorPurple;
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = myBtn;
mypin.draggable = NO;
mypin.highlighted = YES;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
return mypin;
}
Now use the following delegate whenever the button in annotationView will get tapped the following delegate will be called from where you can easly get which particular annotaion's button is tapped
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
annotation *annView = view.annotation;
detailedViewOfList *detailView = [[detailedViewOfList alloc]init];
detailView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
detailView.address = annView.address;
detailView.phoneNumber = annView.phonenumber;
[self presentModalViewController:detailView animated:YES];
OR
[self.navigationController pushViewController:detailView animated:YES];
}
here annotaion is a class importing MKAnnotaion.h and address and phonenumber are properties of annotaion class you can make many more while the address and phoneNumber properties of detailView class are strong. So that you can pass values. Hope this will help you!

Related

Getting MapKit animateDrop to work

Helloall in MapKit I can't figure out how to get the animateDrop animation to run, I'm using 1 viewController with both CoreLocation and MapKit running on it.
I read that I need to make sure I have set a delegate from the mapview to self in viewDidLoad which I have done and also to make sure I am using MKPinAnnotationView to get access to the animateDrop property, which I think I have done also?
I'm building for iOS8 also.
Any help would be great
//I'm not showing all code just showing some of the related parts of code below
.h
//I do set standard imports UIKit, CoreLocation, MapKit etc
#interface ViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>
//I do set various properties related. CLLocationManager, CLLocation, MKMapView
.m
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.delegate = self;
MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init];
myAnnotation.coordinate = CLLocationCoordinate2DMake(37.813186, 144.962979);
myAnnotation.title = #"My title";
myAnnotation.subtitle = #"My sub title";
[self.mapView addAnnotation:myAnnotation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
//pinView.animatesDrop = YES;
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Any help would be great

Callout opening wrong view after zoom in iOS7

Everything is working fine in my app except for one thing: after zooming in and zooming back out, to see the whole map, some callouts open the wrong detailview.
I don't know if I'm missing some code or else.
Using Xcode 5.1.1 for iOS7.
This is what I've got at the moment:
Annotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Annotation: NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
Annotation.m
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate,title,subtitle;
#end
MapView.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface Nameofthemap : UIViewController <MKMapViewDelegate>
#property (strong, nonatomic) IBOutlet MKMapView *Nameofthemap;
#end
MapView.m
#import "MapView.h"
#import "Annotation.h"
#import "InfoViewController.h"
#import "InfoTwoViewController.h"
#interface MapView ()
#property (nonatomic, strong) IBOutlet InfoViewController *InfoViewController;
#property (nonatomic, strong) IBOutlet InfoTwoViewController *InfoTwoViewController;
#end
#define PLACE1_LATITUDE 43.777130;
#define PLACE2_LONGITUDE 10.790018;
#define PLACE2_LATITUDE 43.81471237;
#define PLACE2_LONGITUDE 10.67472765;
#implementation MapView
- (IBAction)changeMapType:(id)sender {
if (_MapView.mapType == MKMapTypeHybrid)
_MapView.mapType = MKMapTypeStandard;
else
_MapView.mapType = MKMapTypeHybrid;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self gotoLocation];
_MapView.showsUserLocation = YES;
}
- (void)gotoLocation
{
MKCoordinateRegion newRegion;
newRegion.center.latitude = PLACE1_LATITUDE;
newRegion.center.longitude = PLACE2_LONGITUDE;
newRegion.span.latitudeDelta = 0.25f;
newRegion.span.longitudeDelta = 0.25f;
[self.MapView setRegion:newRegion animated:YES];
NSMutableArray * locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Annotation *myAnn;
Annotation *myAnn2;
//Place1 annotation
myAnn = [[Annotation alloc] init];
location.latitude = PLACE1_LATITUDE;
location.longitude = PLACE1_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = #"Name of the place";
myAnn.subtitle = #"Details";
[locations addObject:myAnn];
//Place2 annotation
myAnn2 = [[Annotation alloc] init];
location.latitude = PLACE2_LATITUDE;
location.longitude = PLACE2_LONGITUDE;
myAnn2.coordinate = location;
myAnn2.title = #"Name of place two";
myAnn2.subtitle = #"Details";
[locations addObject:myAnn2];
[self->_MapView addAnnotations:locations];
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"Your position";
return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([[myAnn title] isEqualToString:#"Name of the place"]){
[rightButton addTarget:self action:#selector(myAnnClicked:)forControlEvents:UIControlEventTouchUpInside];
}
if ([[myAnn title] isEqualToString:#"Name of place two"]){
[rightButton addTarget:self action:#selector(myAnn2Clicked:)forControlEvents:UIControlEventTouchUpInside];
}
pinView.rightCalloutAccessoryView = rightButton;
}
return pinView;
}
-(IBAction)myAnnClicked:(id)sender
{
InfoViewController *info = [[InfoViewController alloc]init];
[self.navigationController pushViewController:info animated:YES];
}
-(IBAction)myAnn2Clicked:(id)sender
{
InfoTwoController *info2 = [[InfoTwoController alloc]init];
[self.navigationController pushViewController:info2 animated:YES];
}
#end
It's an annotation view re-use issue.
In viewForAnnotation, the button targets are only being set when creating a view (if dequeueReusableAnnotationViewWithIdentifier returns nil).
But if dequeueReusableAnnotationViewWithIdentifier returns a previously-used view, the button target is still whatever was set for the annotation that used the view before.
That previous annotation may not be the same as the current annotation.
So it's possible for annotation "two" to re-use a view that was originally created for annotation "one" and tapping on the already-created button shows the info for "one" instead of "two".
To fix this, two things should be done:
If dequeueReusableAnnotationViewWithIdentifier returns a view (if pinView is not nil), the code must update the view's annotation property to the current annotation.
The button target must be set whether a new view is being created or a dequeued view is being re-used. The easiest way to do this is to move the button creation/setting after the main if and just before the return.
The updated viewForAnnotation would look like this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"Your position";
return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
}
else
{
//1. Re-using a view, update which annotation it's being used for now
pinView.annotation = myAnn;
}
//2. Now pinView is either a new view or re-used view.
//Set its button target based on current annotation...
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([[myAnn title] isEqualToString:#"Name of the place"]){
[rightButton addTarget:self action:#selector(myAnnClicked:)forControlEvents:UIControlEventTouchUpInside];
}
if ([[myAnn title] isEqualToString:#"Name of place two"]){
[rightButton addTarget:self action:#selector(myAnn2Clicked:)forControlEvents:UIControlEventTouchUpInside];
}
pinView.rightCalloutAccessoryView = rightButton;
return pinView;
}
By the way, instead of creating separate methods for each annotation (which can get tedious), use the map view's calloutAccessoryControlTapped delegate method instead.
In fact, right now, the map view is calling both your custom methods and the calloutAccessoryControlTapped delegate method (in which there's no code currently).
In the delegate method, the annotation tapped is accessible via view.annotation.
So in viewForAnnotation, you would just do this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"Your position";
return nil;
}
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pinView"];
if (!pinView) {
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:myAnn reuseIdentifier:#"pinView"];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
pinView.annotation = myAnn;
}
return pinView;
}
Then in the calloutAccessoryControlTapped delegate method, you can do something like this:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
if ([view.annotation isKindOfClass:[Annotation class]])
{
Annotation *myAnn = (Annotation *)view.annotation;
id vcToPush = nil;
if ([[myAnn title] isEqualToString:#"Name of the place"]) {
vcToPush = [[InfoViewController alloc]init];
}
else if ([[myAnn title] isEqualToString:#"Name of place two"]) {
vcToPush = [[InfoTwoController alloc]init];
}
[self.navigationController pushViewController:vcToPush animated:YES];
}
}
Then remove the myAnnClicked and myAnn2Clicked methods.
You would also be much better off creating a generic "Info" view controller instead of a separate one for each annotation.
Some other unrelated things:
Don't put a semi-colon at the end of the #define lines
You've defined PLACE2_LONGITUDE twice
newRegion.center is using PLACE2_LONGITUDE instead of PLACE1_LONGITUDE

didSelectAnnotationView method creates an error

In my app, I have a mapView and few other components.
I have changed the view of annotation into my own icons, the icons gets displayed in the specific location of the the latitude and longitude.
But, when I click and hold the icons, it automatically gets converted into the anotations.
Please help me.
This is my map while loading
It becomes as such When I click and hold the annotations
didUpdateUserLocation
{
CLLocationCoordinate2D first;
first.latitude=13.040202;
first.longitude=80.24298;
myAnnotation.coordinate=first;
[locations addObject:myAnnotation];
[self.mapView addAnnotations:locations];
}
viewForAnnotation:
{
static NSString *identifier = #"Wifintech";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if ( pinView == nil )
pinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.image = [UIImage imageNamed:#"car-side.png"];
pinView.canShowCallout = YES;
}
didSelectAnnotationView
{
float latitude = [[view annotation ] coordinate].latitude;
float longitude = [[view annotation ] coordinate].longitude;
title_value=[[view annotation] title];
NSString * subtitle_val =[[view annotation] subtitle];
title_para.text=[NSString stringWithFormat:#"%#, %#",title_value,subtitle_val];
latitude_value.text=[NSString stringWithFormat:#"%f",latitude];
longitude_value.text=[NSString stringWithFormat:#"%f",longitude];
}
When using your own images, you need to create an MKAnnotationView not an MKPinAnnotationView. Please try searching on SO for answers before posting questions (it will save everyone including you a lot of time) .
MKAnnotationView ClassReference
Try returning a MKAnnotationView instead of MKPinAnnotationView from
-mapView:viewForAnnotation:
Most likely the subclass overrides some method that are tracking the selected-state of the view and adjusting the image. I suspect this will not be the case when using MKAnnotationView.
I think you need to take a close look at the following documentation.
Also, maybe make sure that the view in didSelect.. method is actually a pinAnnotionView and that the image is what you think it is.
From the documentation on MKAnnotationView:
Annotation views support the concept of a selection state, which determines whether the view is unselected, selected, or selected and displaying a standard callout view. The user toggles between the selection states through interactions with the annotation view. In the unselected state, the annotation view is displayed but not highlighted. In the selected state, the annotation is highlighted but the callout is not displayed. And finally, the annotation can be displayed both with a highlight and a callout. The callout view displays additional information such as a title string and controls for viewing more information. The title information is provided by the annotation object but your annotation view is responsible for providing any custom controls. For more information, see the subclassing notes.
This is my code
#import "FirstViewController.h"
#import "LocationObject.h"
#define THE_SPAN 0.01f;
#interface FirstViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (weak, nonatomic) IBOutlet UITextField *latitude_value;
#property (weak, nonatomic) IBOutlet UITextField *longitude_value;
#property (copy, nonatomic) NSString *title_value;
#property(nonatomic,assign) CLLocationCoordinate2D myCoordinate;
#property(nonatomic,copy) NSMutableArray *locations;
#property(nonatomic,retain) MKPointAnnotation * myAnnotation;
#property (readwrite) int tag;
#property(retain) MKPinAnnotationView *pinView;
#property (weak, nonatomic) IBOutlet UITextView *title_para;
#property(assign) CLLocationCoordinate2D *coordsArray;
#property(nonatomic,assign) MKPolyline * routeLine;
#end
#implementation FirstViewController
#synthesize latitude_value;
#synthesize longitude_value;
#synthesize title_value;
#synthesize myCoordinate;
#synthesize mapView;
#synthesize locations;
#synthesize myAnnotation;
#synthesize tag;
#synthesize pinView;
#synthesize title_para;
#synthesize title;
#synthesize coordsArray;
#synthesize routeLine;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setMapView:nil];
[self setLatitude_value:nil];
[self setLongitude_value:nil];
[self setLatitude_value:nil];
[self setLongitude_value:nil];
[self setTitle_value:nil];
[self setTitle_para:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polyLineView = [[MKPolylineView alloc] initWithPolyline:routeLine];
polyLineView.fillColor = [UIColor blueColor];
polyLineView.strokeColor = [UIColor redColor];
polyLineView.lineWidth = 2;
return polyLineView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
//map view : region nad annotation
#pragma mark map view delegate methods
-(void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//map region and center location
MKCoordinateRegion myRegion;
CLLocationCoordinate2D center;
center.latitude=13.040223;
center.longitude=80.240995;
MKCoordinateSpan span;
span.latitudeDelta=THE_SPAN;
span.longitudeDelta=THE_SPAN;
myRegion=MKCoordinateRegionMake(center, span);
MKCoordinateRegion adjusted_region=[self.mapView regionThatFits:myRegion];
[self.mapView setRegion:adjusted_region animated:YES];
locations=[[NSMutableArray alloc]init];
//first point
CLLocationCoordinate2D first;
first.latitude=13.040202;
first.longitude=80.24298;
myAnnotation = [[MKPointAnnotation alloc]init];
myAnnotation.coordinate=first;
myAnnotation.title=#"Wifin Technology";
myAnnotation.subtitle=#"Globus";
[locations addObject:myAnnotation];
//second point
CLLocationCoordinate2D second;
second.latitude=13.0406527;
second.longitude=80.2437427;
myAnnotation= [[MKPointAnnotation alloc]init];
myAnnotation.coordinate=second;
myAnnotation.title=#"The Residency Towers";
myAnnotation.subtitle=#"Chennai";
[locations addObject:myAnnotation];
//third point
CLLocationCoordinate2D third;
third.latitude=13.040202;
third.longitude=80.240191;
myAnnotation= [[MKPointAnnotation alloc]init];
myAnnotation.coordinate=third;
myAnnotation.title=#"Rado Cool Zone";
myAnnotation.subtitle=#"Chennai";
[locations addObject:myAnnotation];
[self.mapView addAnnotations:locations];
title_para.text=[[NSString alloc]initWithString:#"The position displayed is Pondy Bazaar"];
coordsArray = malloc(sizeof(CLLocationCoordinate2D) * locations.count);
int i = 0;
for (CLLocation *loc in locations) {
coordsArray[i] = loc.coordinate;
i++;
}
routeLine = [MKPolyline polylineWithCoordinates:coordsArray
count:locations.count];
[mapView addOverlay:routeLine];
self.longitude_value.text=[NSString stringWithFormat:#"%f",center.longitude];
self.latitude_value.text=[NSString stringWithFormat:#"%f",center.latitude];
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
float latitude = [[view annotation ] coordinate].latitude;
float longitude = [[view annotation ] coordinate].longitude;
title_value=[[view annotation] title];
NSString * subtitle_val =[[view annotation] subtitle];
title_para.text=[NSString stringWithFormat:#"%#, %#",title_value,subtitle_val];
latitude_value.text=[NSString stringWithFormat:#"%f",latitude];
longitude_value.text=[NSString stringWithFormat:#"%f",longitude];
}
//Annotation view: icons
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
{
pinView = nil;
static NSString *identifier = #"Wifintech";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if ( pinView == nil )
pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:identifier];
if([[annotation title] isEqualToString:#"Wifin Technology"])
{
pinView.image = [UIImage imageNamed:#"car-side.png"];
pinView.canShowCallout = YES;
}
else if ([[annotation title] isEqualToString:#"The Residency Towers"])
{
pinView.image=[UIImage imageNamed:#"lorry-side.png"];
pinView.canShowCallout = YES;
}
else if([[annotation title] isEqualToString:#"Rado Cool Zone"])
{
//pinView.pinColor = MKPinAnnotationColorGreen;
pinView.canShowCallout = YES;
//pinView.animatesDrop = YES;
pinView.image = [UIImage imageNamed:#"car.png"];
}
else {
NSLog(#"Nothing");
}
return pinView;
}
#end

custom data variables in mkannotation

I have a map view controller (UIViewController, MKMapView), with its delegate (HCIResultMapViewController).
I wish to have following functionality in this part.
1). I wish to use my custom made NSObject , so that I can associate others details along with the basic entities like title, subtitle etc.
Hence according to my needs I coded as following
In HCIResultMapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_houseList = [[_resultList objectForKey:#"result"] objectForKey:#"listings"];
// NSLog([_houseList description]);
int i = 0;
for (NSDictionary *house in _houseList) {
HCIAnnotationViewController *annotation = [[HCIAnnotationViewController alloc]
initwithHouse:house];
[_mapView addAnnotation:annotation];
// NSLog(#"asdjhasdjsajdhaksdjghasdasdjahsdahskvdka");
self.currIdentifier = i;
i++;
}
[_mapView setShowsUserLocation:NO];
}
The other delegate functions
-(void) mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
for (NSObject<MKAnnotation> *annotation in _mapView.selectedAnnotations) {
NSLog(#"hellomaster");
NSLog(annotation.title);
if ([annotation isKindOfClass:[HCIAnnotationViewController class]]) {
NSLog(#"hellomaster");
}
}
The last one
-(MKAnnotationView*) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
NSString *identifier = #"currIdentifier";
MKPinAnnotationView *annotationView =
(MKPinAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation
reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.tag = self.currIdentifier;
// Create a UIButton object to add on the
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[annotationView setRightCalloutAccessoryView:rightButton];
/*
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[leftButton setTitle:annotation.title forState:UIControlStateNormal];
[annotationView setLeftCalloutAccessoryView:leftButton];
*/
return annotationView;
}
But I see that the class equivalence fails. Can you tell me what I'm doing wrong?
I think what I want, in simple words, is, how can I send some data (NSDictionary*) along with a annotation such that I can retrieve it whenever I want?
Please dont tag this as repeated question or so. I have tried many questions, googling etc. but couldn't find a suitable solution for this.
Here You can also set NSMutableDictionary instand of NSString.
Create custom AnnotationView:
#import <MapKit/MapKit.h>
#interface AnnotationView : MKPlacemark
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, strong) NSString *title; //Here You cam set `NSMutableDictionary` instand of `NSString`
#property (nonatomic, strong) NSString *subtitle; //Here You cam set `NSMutableDictionary` instand of `NSString`
#end
And in .m file
#import "AnnotationView.h"
#implementation AnnotationView
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary
{
if ((self = [super initWithCoordinate:coordinate addressDictionary:addressDictionary]))
{
self.coordinate = coordinate;
}
return self;
}
#end
// Use Annotation Add #import "AnnotationView.h" in your relevant .m file:
CLLocationCoordinate2D pCoordinate ;
pCoordinate.latitude = LatValue;
pCoordinate.longitude = LanValue;
// Create Obj Of AnnotationView class
AnnotationView *annotation = [[AnnotationView alloc] initWithCoordinate:pCoordinate addressDictionary:nil] ;
annotation.title = #"I m Here";
annotation.subtitle = #"This is Sub Tiitle";
[self.mapView addAnnotation:annotation];
I couldn't find exact way to implement custom data variables or the reason why my class equivalence fails. But I figured out a way to over come this kind of situation. This might be redundant in method, but still works like a charm.
So the idea is to use the tagging system in control button. I observed that every time I send a message to my map view to add a annotation it immediately calls my viewforannotation method. Since I'm iterating through an array, I maintained a index global pointer, with which I set tag of the control button. Later when the button is clicked, I retrieve the tag and use it to get the object I want.
Anyone else have any alternative or direct solution, please do post.

Problems with MapView Pin Annotation - Pin loses color when map is zoomed/panned/region changes

I have a mapview that displays locations of cash points. Annotations are dropped and the callout can be clicked on to go to a page with more detail about that location. There are two categories of cashpoint, free and paid, free cashpoint pins are green and the other red. When the pins drop they are the correct colours. Everything works fine untill i zoom to user location or other areas of the map then when i go back to the pins they have lost their colour formatting and are all the original red colour.
I assume this is something to do with the map reloading when it downloads tiles and not reloading the pins properly, although i could be wrong.
Any help will be much appreciated.
here is my code:
#import "CashPointMapViewController.h"
#import "PinDrop.h"
#import "CashPointDetailViewController.h"
#implementation CashPointMapViewController
#synthesize app, theCashList, mapview, ann, count, myArray, pinColor;
- (IBAction) getlocation {
MKCoordinateRegion region;
region.center = self.mapview.userLocation.coordinate;
region.span.longitudeDelta = 0.01f;
region.span.longitudeDelta = 0.01f;
[mapview setRegion:region animated:YES];
}
- (void)viewDidLoad {
[super viewDidLoad];
mapview.showsUserLocation = YES;
[mapview setMapType:MKMapTypeStandard];
[mapview setZoomEnabled:YES];
[mapview setScrollEnabled:YES];
MKCoordinateRegion region = { {0.0, 0.0 }, {0.0, 0.0 } };
region.center.latitude = 53.801279;
region.center.longitude = -1.548567;
region.span.longitudeDelta = 0.3f;
region.span.longitudeDelta = 0.3f;
[mapview setRegion:region animated:YES];
app = [[UIApplication sharedApplication]delegate];
UIImage *locate = [UIImage imageNamed:#"location arrow white.png"];
UIBarButtonItem *userlocatebutton = [[UIBarButtonItem alloc] initWithImage:locate style:UIBarButtonItemStylePlain target:self action:#selector(getlocation)];
self.navigationItem.rightBarButtonItem = userlocatebutton;
[self performSelectorInBackground:#selector(annloop) withObject:self];
}
-(void) annloop {
int i;
for (i=0; i<=count-1; i = i+1) {
theCashList = [myArray objectAtIndex:i];
NSString *trimlat = [theCashList.lat stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *trimlon = [theCashList.lon stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
double latdouble = [trimlat doubleValue];
double londouble = [trimlon doubleValue];
CLLocationCoordinate2D coord = {(latdouble),(londouble)};
ann = [[PinDrop alloc] init];
ann.index = i;
ann.title = [theCashList.name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *street = [theCashList.street stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *town = [theCashList.town stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *postcode = [theCashList.postcode stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *address = [[NSString alloc] initWithFormat:#"%#, %#, %#", street, town, postcode];
ann.subtitle = address;
ann.coordinate = coord;
NSString *trimprice = [theCashList.price stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([trimprice isEqualToString:#"Free"])
{
ann.price = 1;
}
else
{
ann.price = 0;
}
[mapview performSelectorOnMainThread:#selector(addAnnotation:) withObject:ann waitUntilDone:YES];
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:ann reuseIdentifier:#"current"];
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = goToDetail;
mypin.draggable = NO;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
if (ann.price == 1)
{
mypin.pinColor = MKPinAnnotationColorGreen;
}
else
{
mypin.pinColor = MKPinAnnotationColorRed;
}
return mypin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control {
PinDrop *annView = view.annotation;
CashPointDetailViewController *detailView = [[CashPointDetailViewController alloc]init];
theCashList = [myArray objectAtIndex:annView.index];
detailView.theCashList = theCashList;
[self.navigationController pushViewController:detailView animated:YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
EDIT: Here is my .h if it helps.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "CashPointList.h"
#import <MapKit/MapKit.h>
#import "PinDrop.h"
#interface CashPointMapViewController : UIViewController {
MKMapView *mapview;
PinDrop *ann;
}
#property (nonatomic, retain) AppDelegate *app;
#property (nonatomic, retain) CashPointList *theCashList;
#property (nonatomic, retain) PinDrop *ann;
#property (nonatomic, retain) IBOutlet MKMapView *mapview;
#property (nonatomic, readwrite) int count;
#property (nonatomic, retain) NSMutableArray *myArray;
#property (nonatomic) MKPinAnnotationColor pinColor;
-(IBAction) getlocation;
#end
It's not a problem related to the map reloading tiles.
The issue is that the code in the viewForAnnotation delegate is using the ann object with the incorrect assumption that the class-instance-level ann object will be in sync with whenever the delegate method is called.
The viewForAnnotation delegate is not necessarily called in the order that you add annotations and can be called multiple times for the same annotation if the map needs to re-display an annotation when it comes back into view.
When the delegate method gets called again for a previously added annotation, ann and annotation no longer point to the same object. ann is now probably pointing to the last added annotation and so all the annotations change to its color.
In that delegate method, you must use the annotation parameter which is a reference to the annotation that the map view wants the view for in the current call (which may be completely unrelated to your outside loop).
So this line:
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]
initWithAnnotation:ann reuseIdentifier:#"current"];
should be:
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"current"];
^^^^^^^^^^
and when checking the annotation's properties, use the annotation parameter (and cast it to your custom class to get at the custom properties):
PinDrop *ann = (PinDrop *)annotation;
//Note that this local "ann" is NOT the same as the class-level "ann".
//May want to use a different name to avoid confusion.
//The compiler may also warn you about this.
if (ann.price == 1)
...
A separate, unrelated, but highly recommended suggestion is to implement annotation view re-use by using dequeueReusableAnnotationViewWithIdentifier. This will improve performance when you have lots of annotations.

Resources