I am displaying a pin on the map but I am not able to customize the display of the annotation view. For some reason my viewForAnnotation is not being called. Here is didFinishLaunchingWithOptions method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[mapView setDelegate:self];
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[mapView setShowsUserLocation:YES];
// Override point for customization after application launch.
[self.window makeKeyAndVisible];
return YES;
}
And here is my viewForAnnotation method which is never being called.
- (MKAnnotationView *)mv:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"viewForAnnotation");
if([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *annotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
[pinView setPinColor:MKPinAnnotationColorGreen];
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
UIImageView *houseIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"house.png"]];
pinView.leftCalloutAccessoryView = houseIconView;
[houseIconView release];
return pinView;
}
and here is didUpdateUserLocation method:
- (void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSTimeInterval t = [[[userLocation location] timestamp] timeIntervalSinceNow];
if(t < -180) return;
NSLog(#"%#",[textField text]);
MapPoint *mp = [[MapPoint alloc] initWithCoordinate:userLocation.location.coordinate title:[textField text]];
[mv addAnnotation:mp];
[mp release];
}
The viewForAnnotation delegate method must be named mapView:viewForAnnotation:.
Your method is named mv:viewForAnnotation:.
Edit:
Here is an example with the two other changes suggested in my comments:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"viewForAnnotation");
if([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *annotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *) [mapView
dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (!pinView)
{
pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation
reuseIdentifier:annotationIdentifier] autorelease];
[pinView setPinColor:MKPinAnnotationColorGreen];
pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
UIImageView *houseIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"house.png"]];
pinView.leftCalloutAccessoryView = houseIconView;
[houseIconView release];
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
Related
in my first iOS app I've got a map displaying annotations for several locations. It works perfectly in the simulator and looks like this:
But on all devices the annotations are not located right. They are all placed at latitude 0 and longitude 0.
Do you have any ideas?
Here is my Source Code:
MapViewController.m
//
// MapViewController.m
//
#import "MapViewController.h"
#import "AppDelegate.h"
#import "Location.h"
#import <MapKit/MapKit.h>
#import "Reachability.h"
#import "MyAnnotation.h"
#interface MapViewController ()
#end
#implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.mapView.delegate = self;
//User location
self.locationManager = [[CLLocationManager alloc]init];
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
[self loadOfflineMap];
[self addAnnotations:[(AppDelegate *)[[UIApplication sharedApplication] delegate] locations]];
//Set initial region
MKCoordinateRegion region = [self.mapView regionThatFits:MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(53.868223, 10.689060), 3000, 3000)];
//Set initial locatoin if one is set
if(self.initialLocationName != nil){
for (id<MKAnnotation> annotation in [self.mapView annotations]) {
if([[annotation title] isEqualToString:self.initialLocationName]){
[self.mapView selectAnnotation:annotation animated:YES];
region = [self.mapView regionThatFits:MKCoordinateRegionMakeWithDistance([annotation coordinate], 500, 500)];
}
}
}
[self.mapView setRegion:region animated:YES];
//Layout stuff
self.locationName.font = [UIFont fontWithName:#"CenturyGothic" size:self.locationName.font.pointSize];
self.locationAddress.font = [UIFont fontWithName:#"CenturyGothic" size:self.locationAddress.font.pointSize];
}
-(void)addAnnotations:(NSMutableArray *)locations{
self.locationNameToAnnotation = [[NSMutableDictionary alloc] init];
for(Location *location in locations){
MyAnnotation *annotation = [[MyAnnotation alloc] initWithTitle:location.name AndCoordinate:CLLocationCoordinate2DMake([location.latitude doubleValue], [location.longitude doubleValue])];
[self.locationNameToAnnotation setObject:annotation forKey:location.name];
[self.mapView addAnnotation:annotation];
}
}
-(void)mapView:(MKMapView * )mapView didSelectAnnotationView:(MKAnnotationView * )view{
for(NSString *locationName in self.locationNameToAnnotation){
if([locationName isEqualToString:view.annotation.title]){
Location *location = [Location getLocationFromLocations:[(AppDelegate *)[[UIApplication sharedApplication] delegate] locations] byName:locationName];
self.locationName.text = location.name;
self.locationAddress.text = location.address;
}
}
self.locationInfoView.hidden = NO;
[self.mapView setCenterCoordinate:view.annotation.coordinate animated:YES];
}
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
self.locationInfoView.hidden = YES;
}
-(void)loadOfflineMap{
self.mapView.delegate = self;
NSString *baseURL = [[[NSBundle mainBundle] bundleURL] absoluteString];
NSString *template = [baseURL stringByAppendingString:#"{x}-{y}.jpg"];
self.overlay = [[MKTileOverlay alloc] initWithURLTemplate:template];
self.overlay.canReplaceMapContent = YES;
self.overlay.minimumZ = 12;
self.overlay.maximumZ = 19;
[self.mapView addOverlay:self.overlay level:MKOverlayLevelAboveLabels];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
}
- (IBAction)mapTypeChanged:(UISegmentedControl *)sender {
if(sender.selectedSegmentIndex == 1){
if([self checkIntetnetConnection] == YES){
[self.mapView removeOverlay:self.overlay];
}else{
sender.selectedSegmentIndex = 0;
}
}else if(sender.selectedSegmentIndex == 0){
[self.mapView addOverlay:self.overlay level:MKOverlayLevelAboveLabels];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)checkIntetnetConnection{
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
//NSLog(#"There IS NO internet connection");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Internet" message:#"Sorry, please turn on your internet to access the online map" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return NO;
} else {
//NSLog(#"There IS internet connection");
return YES;
}
}
#end
MyAnnotation.m
//
// MyAnnotation.m
//
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize coordinate=_coordinate;
#synthesize title=_title;
-(id) initWithTitle:(NSString *) title AndCoordinate:(CLLocationCoordinate2D)coordinate
{
self = [super init];
_title = title;
_coordinate = coordinate;
return self;
}
#end
Edit 1
Locations Array Parsing from JSON, which works fine:
-(void)createLocations:(NSDictionary *)jsonLocations{
self.locations = [[NSMutableArray alloc] init];
for(NSDictionary *jsonLocation in jsonLocations){
Location *location = [[Location alloc] init];
[location setName:jsonLocation[#"name"]];
[location setId:jsonLocation[#"id"]];
[location setLatitude:[self getNumberFromString:jsonLocation[#"latitude"]]];
[location setLongitude:[self getNumberFromString:jsonLocation[#"longitude"]]];
[location setZoomlevel:jsonLocation[#"zoomlevel"]];
[location setAddress:jsonLocation[#"address"]];
[self.locations addObject:location];
}
}
I'd really appreciate all ideas. Probably it's an easy question but since I'm new to iOS Development I'm quite frustrated right now.
Cheers Thomas!
I tired to get indexpath of my custom annotation ,
I use this code for get my indexpath
NSUInteger index =[mapView.annotations indexOfObject:view.annotation];
its not really working because in my map, i got right lat and lang but not get the true data of pinview
pusingpalagw is my subclass
here is my code:
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
// [(UIImageView *)view.leftCalloutAccessoryView setImageWithURL:[NSURL URLWithString:self.content.MERCHANT_IMAGE] usingActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
//if ([view.annotation isKindOfClass:[pusingpalagw class]]) {
// pusingpalagw *annot = view.annotation;
//NSInteger index = [self.arrayOfAnnotations indexOfObject:annot];
NSUInteger index =[mapView.annotations indexOfObject:view.annotation];
if (!self.content) {
pusingpalagw *calloutView = [[pusingpalagw alloc] initWithFrame:CGRectMake(0.0, 0.0, 242.0, 57.0)];
self.content12 = [self.listContent objectAtIndex:index];
calloutView.titleLabel.text = self.content12.MERCHANT_NAME;
calloutView.subtitleLabel.text = self.content12.MERCHANT_NAME;
//UIView *rating2 = (UIView*)[cell2 viewWithTag:110];
_starRating = [[EDStarRating alloc]initWithFrame:CGRectMake(calloutView.viewRating.frame.origin.x-15, calloutView.viewRating.frame.origin.y,80,20)];
_starRating.backgroundColor = [UIColor clearColor];
self.starRating.starImage = [UIImage imageNamed:#"kuningstarkosong"];
self.starRating.starHighlightedImage = [UIImage imageNamed:#"kuningstarfull"] ;
_starRating.maxRating = 5.0;
_starRating.delegate = self;
_starRating.horizontalMargin = 15.0;
_starRating.editable=NO;
_starRating.rating= [self.content12.MERCHANT_RATTING floatValue];
_starRating.displayMode=EDStarRatingDisplayHalf;
[_starRating setNeedsDisplay];
[calloutView.viewRating addSubview:_starRating];
NSLog(#"keluarbintang%#",_starRating);
NSURL *url = [NSURL URLWithString:self.content12.MERCHANT_IMAGE];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *abs = [UIImage imageWithData:imageData];
[calloutView.imageMap setImage:abs];
//[calloutView.buttonDetail setTitle: #"Post" forState: UIControlStateNormal];
UIButton *buttonAja = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, calloutView.frame.size.width, calloutView.frame.size.height)];
[buttonAja setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//[buttonAja setTitle: #"Post" forState: UIControlStateNormal];
buttonAja.titleLabel.font = [UIFont systemFontOfSize:13.0];
[buttonAja addTarget:self action:#selector(goDetail:) forControlEvents:UIControlEventTouchUpInside];
[calloutView addSubview:buttonAja];
calloutView.center = CGPointMake(CGRectGetWidth(view.bounds) / 2.0, 0.0);
[view addSubview:calloutView];
}
//To get permission
if([CLLocationManager locationServicesEnabled]){
NSLog(#"Location Services Enabled");
if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied){
alert = [[UIAlertView alloc] initWithTitle:#"App Permission Denied"
message:#"To re-enable, please go to Settings and turn on Location Service for this app."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
//To set user Location
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.showsUserLocation=YES;
self.mapView.delegate = self;
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
}
...
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.2;
mapRegion.span.longitudeDelta = 0.2;
[mapView setRegion:mapRegion animated: YES];
}
Permission for IOS 8 Or Later :-
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
if ([CLLocationManager locationServicesEnabled] )
{
if (self.locationManager == nil )
{
self.locationManager.delegate = (id)self;
self.locationManager = [[CLLocationManager alloc] init];
#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.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kDistanceFilter; //kCLDistanceFilterNone// kDistanceFilter;
}
[self.locationManager startUpdatingLocation];
self.mapViewForPlace.showsUserLocation = YES;
[self.locationManager setDelegate:self];
NSLog(#"Location Title Is: %#", self.mapViewForPlace.userLocation.title);
}
Add info.plist NSLocationWhenInUseUsageDescription type of string.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
#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.mapViewForPlace.showsUserLocation = YES;
self.currentLocation = [locations lastObject];
// here we get the current location
NSLog(#"Current Locations : %#",self.currentLocation);
// CLLocation* location = (CLLocation*)locations.lastObject;
// Use Apple's Geocoder to figure the name of the place
CLGeocoder* geoCoder = [[CLGeocoder alloc] init];
[geoCoder reverseGeocodeLocation:self.currentLocation completionHandler: ^(NSArray* placemarks, NSError* error) {
if (error != nil) {
NSLog(#"Error in geo coder: %#", error);
}
else {
if (placemarks.count == 0) {
NSLog(#"The address couldn't be found");
}
else {
// Get nearby address
CLPlacemark* placemark = placemarks[0];
// Get the string address and store it
NSString* locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//location.name = locatedAt;
currentLocationNameIs=locatedAt;
NSLog(#"The address is: %#", locatedAt);
}
}
}];
}
- (void) locationManager:(CLLocationManager *) manager didUpdateToLocation:(CLLocation *) newLocation fromLocation:(CLLocation *) oldLocation
{
self.currentLocation = newLocation;
self.mapViewForPlace.showsUserLocation = YES;
NSLog(#"New location Cordinate : %f %f",self.mapViewForPlace.userLocation.coordinate.latitude,self.mapViewForPlace.userLocation.coordinate.longitude);
[self.locationManager stopUpdatingLocation];
}
- (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.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
//pinView.animatesDrop = YES;
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"facebook30.png"];
pinView.calloutOffset = CGPointMake(0, 32);
// Add a detail disclosure button to the callout.
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = rightButton;
// Add an image to the left callout.
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"facebook30.png"]];
pinView.leftCalloutAccessoryView = iconView;
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
I don't know what's wrong with my code. This code work fine in iphone5 to higher version. In the first load of controller the map will show the country first then zoom in where the user point and the annotation show. Unfortunately, the iphone4s work different. It shows only the country then no more point or annotation show.
here is my code:
#import "ViewController.h"
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#interface ViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic,strong) CLLocationManager * locationManager;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
self.mapView.showsUserLocation = YES;
}
}
#pragma mark Map View
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *identifier = #"getLocation";
MKAnnotationView *annotationView = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
[self.mapView setShowsUserLocation:NO];
[self.mapView removeAnnotations:self.mapView.annotations];
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:userLocation.coordinate.latitude longitude:userLocation.coordinate.longitude];
CLGeocoder * geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemark, NSError *error) {
NSString *annTitle = #"Address unknown";
if (placemark.count > 0)
{
CLPlacemark *topResult = [placemark objectAtIndex:0];
annTitle = [NSString stringWithFormat:#"%#", topResult.locality];
}
MKPointAnnotation *toAdd = [[MKPointAnnotation alloc]init];
toAdd.coordinate = userLocation.coordinate;
toAdd.title =annTitle;
[self.mapView addAnnotation:toAdd];
}];
}
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views{
MKAnnotationView *annotationView = [views objectAtIndex:0];
id<MKAnnotation> mp = [annotationView annotation];
[UIView animateWithDuration:3.0 animations:^{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,500,500);
[self.mapView setRegion:region animated:YES];
} completion:^(BOOL finished) {
[self.mapView selectAnnotation:mp animated:YES];
}];
}
and my viewcontroller.m
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <MKMapViewDelegate, MKAnnotation,CLLocationManagerDelegate>
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#end
but I get this error
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
The errors shows only for iphone4s. The version of my iphone4s is ios8.
This is happening because you have not made entry in plist as shown below.
If still not working, update code to below.
myMapView.delegate = self;
locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
#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];
myMapView.showsUserLocation = YES;
[myMapView setMapType:MKMapTypeStandard];
[myMapView setZoomEnabled:YES];
[myMapView setScrollEnabled:YES];
Edit 1
As per your comment, you don't find info.plist.
You can find that in Supporting files.
my problem is rather simple but I can not seem to figure it out.
I am trying to add a refresh button to my mapview that will go back to the server and retrieve new locations if there have been any updates. My code below can already make the first call to the server with viewdidload method and can plot all the locations on the server to the map. What I need now is for a button that will make this same call whenever pressed, I am using one class for all my code so please your simplest solution that will easily merge with the code will be very much appreciated.
I am also very new to ios programming so any advice on how to tidy up my code will be also appreciated.
This is my view controller that contains all my code.
//ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.delegate = self;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
[self.mapView setShowsUserLocation:YES];
} else {
[locationManager requestWhenInUseAuthorization];
}
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://sample.name/service.php"];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_downloadedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSMutableArray *_locations = [[NSMutableArray alloc] init];
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData options:NSJSONReadingAllowFragments error:&error];
CLLocationCoordinate2D coordinate;
for (int i = 0; i < jsonArray.count; i++)
{
NSDictionary *jsonElement = jsonArray[i];
MKPointAnnotation* marker = [[MKPointAnnotation alloc] init];
marker.title = jsonElement[#"Name"];
marker.subtitle = jsonElement[#"Address"];
coordinate.latitude = [jsonElement [#"Latitude"] doubleValue];
coordinate.longitude = [jsonElement [#"Longitude"] doubleValue];
marker.coordinate = coordinate;
[_locations addObject:marker];
}
[self.mapView addAnnotations:_locations];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *identifier;
{
if (annotation == mapView.userLocation) return nil;
MKAnnotationView *annotationView;
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"blue_pin.png"];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[self.mapView setShowsUserLocation:YES];
}
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D myLocation = [userLocation coordinate];
MKCoordinateRegion zoomRegion = MKCoordinateRegionMakeWithDistance(myLocation, 10000, 10000);
[self.mapView setRegion:zoomRegion animated:YES];
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)InterfaceOrientation
{
return (InterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Refresh:(id)sender {
}
#end
You can find my solution with comment.
Remove your old data when you refresh or when you got the response.
- (IBAction)action_goToManageDevice:(id)sender
{
[self reloadData];
}
- (void)reloadData
{
// Remove old annotation
[self.mapView removeAnnotations:self.mapView.annotations];
// reload your data
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://sample.name/service.php"];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
I have a "problem" with the following code. The error message is: Application tried to push a nil view controller on target UINavigationController:0x10b82bbf0 when clicking on annotation #4's callout.
How can I make it open an alertview without getting this error?
//Callout button action
- (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:#"1. Annotation one"]){
vcToPush = [[FirstViewController alloc]init];
}
if ([[myAnn title] isEqualToString:#"2. Annotation two"]){
vcToPush = [[SecondViewController alloc]init];
}
if ([[myAnn title] isEqualToString:#"3. Annotation three"]){
vcToPush = [[ThirdViewController alloc]init];
}
if ([[myAnn title] isEqualToString:#"4. Annotation four"]){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Fourth annotation" message:#"Message" delegate:nil cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
[self.navigationController pushViewController:vcToPush animated:YES];
}
}
//Custom callout
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)myAnn {
//Current location blue dot
if ([myAnn isKindOfClass:[MKUserLocation class]])
{
((MKUserLocation *)myAnn).title = #"My 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;
}
Thank you!
In the if block
if ([[myAnn title] isEqualToString:#"4. Annotation four"]){
vcToPush is not initialize. Therefore is has the value it had before the method got called (nil in this case).
I assume you only want to show an alert in case of #4. In this case, add a return in the if block:
if ([[myAnn title] isEqualToString:#"4. Annotation four"]){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Fourth annotation" message:#"Message" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
return;
}