MapView search places are visible on wrong co-ordinates - ios

I have develop an application in iOS 7.0. I have a map view in which user can see search results in map by means of annotation pins.
I have used custom annotation for that, For the first time annotations were placed at correct co ordinates. I mean at user location co ordinates were place at correct position.
But if i scroll map and search for location then it shows me annotation at wrong co ordinates.
Below is my code when user search any thing in map. (e.g Hotels, Museum, Restaurants)
- (void) searchForPlace:(NSString *) keyWord {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.activityView setHidden:NO];
[self.txtSearch resignFirstResponder];
[self.txtSearch setEnabled:NO];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = keyWord; // #"restaurant"
MKCoordinateSpan span = MKCoordinateSpanMake(.1, .1);
CLLocationCoordinate2D location = self.mapView.userLocation.coordinate;
request.region = MKCoordinateRegionMake(location, span);
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];
[search startWithCompletionHandler:
^(MKLocalSearchResponse *response, NSError *error) {
[self.txtSearch setEnabled:YES];
[self removeMapOverlay];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self.activityView setHidden:YES];
if (!error) {
// Result found
#try {
if (response.mapItems && [response.mapItems count] > 0) {
for (MKMapItem *item in response.mapItems) {
MKPlacemark *placeMark = item.placemark;
// Address details
NSDictionary *address = placeMark.addressDictionary;
NSString *titleString = #"";
NSString *subtitleString = #"";
NSString *name = #"";
NSString *Thoroughfare = #"";
NSString *State = #"";
NSString *City = #"";
NSString *Country = #"";
name = [address objectForKey:#"Name"] ? [address objectForKey:#"Name"] : #"";
Thoroughfare = [address objectForKey:#"Thoroughfare"] ? [address objectForKey:#"Thoroughfare"] : #"";
State = [address objectForKey:#"State"] ? [address objectForKey:#"State"] : #"";
City = [address objectForKey:#"City"] ? [address objectForKey:#"City"] : #"";
Country = [address objectForKey:#"Country"] ? [address objectForKey:#"Country"] : #"";
titleString = [NSString stringWithFormat:#"%# %#", name, Thoroughfare];
subtitleString = [NSString stringWithFormat:#"%# %# %#", State, City, Country];
CustomAnnotation *annotation = [[CustomAnnotation alloc] initWithTitle:titleString subTitle:subtitleString detailURL:item.url location:placeMark.location.coordinate];
[self.mapView addAnnotation:annotation];
}
[self mapView:self.mapView regionDidChangeAnimated:YES];
}
}
#catch (NSException *exception) {
NSLog(#"Exception :%#",exception.description);
}
} else {
NSLog(#"No result found.");
}
}];
}

I think it is because of this line:
CLLocationCoordinate2D location = self.mapView.userLocation.coordinate;
What here problem is you are doing search request for region around your user location.
You need to set center co ordinates region of MKMapView. So that region for the search area will be consider where ever you scroll in map.
Change above line with this and check your search result.
CLLocationCoordinate2D location = self.mapView.centerCoordinate;

Related

Obj-C - All Custom MKMapView annotations not always showing on MapView?

I'm trying to display multiple arrays of locations on my mapView with the below code (Restaurants, Parks, Meet Ups & Stores). When I open the app, not all addresses inside the arrays are displayed on my mapView (even though all data is returned) - e.g. sometimes only 'Stores' and 'Parks' arrays of annotations will show up on my map, but Restaurants aren't visible (even though data for all arrays is returned successfully). If I close out and reopen the app, sometimes Parks will show on the map, but nothing else. Any idea why this happens, and how I can fix it? Code updated below. Been at this forever!
Note: ParksAnnotation, RestAnnotation, meetupAnn, & StoreAnnotation are all MKPointAnnotation classes.
UPDATE (10/13/2020): I tried logging 'placemarks' under the block of code that retrieves and geocodes my 'Stores' coordinates. It appears as though self.storeData is populated, as is the created NSDictionary storeFields. That said, when I log 'placemarks', it isn't returning any coordinates, even though storeFields[#"address"] is populated. The other blocks of code seem to be doing their job just fine (ie. retrieving Meet Ups and retrieving Parks). So Meet Ups, Restaurants and Parks annotations appear fine, but all Stores annotations aren't populated. This happens to at least one type of annotation (sometimes it's Stores that's missing, other times it's Parks) at random when I launch the app. I can't for the life of me sort out why this is happening.
See below code:
MapViewController.m
#import "StoreAnnotation.h"
#import "ParksAnnotation.h"
#import "RestAnnotation.h"
#import "meetupAnn.h"
#interface MapViewController ()
#end
#implementation MapViewController
-(void)viewWillAppear:(BOOL)animated {
NSMutableDictionary *viewParamsallUsers1 = [NSMutableDictionary new];
[viewParamsallUsers1 setValue:#"hosted_meet_ups" forKey:#"view_name"];
[DIOSView viewGet:viewParamsallUsers1 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.meetUps = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *allMeetups in self.meetUps) {
NSString *location = allMeetups[#"where"];
NSString *userNames = allMeetups[#"node_title"];
NSString *userBio = allMeetups[#"body"];
self.alertMessage = [allMeetups[#"node_title"] mutableCopy];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
meetupAnn *meet = [[meetupAnn alloc] init];
meet.coordinate = placemark.coordinate;
meet.title = userNames;
meet.subtitle = userBio;
meet.index = index; // Store index here.
[self.mapView addAnnotation:meet];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
/// GRAB ALL RESTAURANT LOCATIONS ///
NSMutableDictionary *viewParams6 = [NSMutableDictionary new];
[viewParams6 setValue:#"restaurants" forKey:#"view_name"];
[DIOSView viewGet:viewParams6 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.neighbourhoodData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *multiplelocationsFriend in self.neighbourhoodData) {
NSString *location = multiplelocationsFriend[#"address"];
NSString *userNames = multiplelocationsFriend[#"node_title"];
NSString *ampRemoved = [userNames stringByReplacingOccurrencesOfString:#"amp;" withString:#""];
NSString *userBio = multiplelocationsFriend[#"body"];
self.x3 = multiplelocationsFriend[#"x3"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
RestAnnotation *point1 = [[RestAnnotation alloc] init];
point1.coordinate = placemark.coordinate;
point1.title = ampRemoved;
point1.subtitle = userBio;
point1.index = index; // Store index here.
[self.mapView addAnnotation:point1];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
NSString *test = self.areaName;
NSLog(#"SHOW TEST %#", test);
/// GRAB ALL STORE LOCATIONS ///
NSMutableDictionary *viewParams7 = [NSMutableDictionary new];
[viewParams7 setValue:#"stores" forKey:#"view_name"];
[DIOSView viewGet:viewParams7 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.storesData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *storeFields in self.storesData) {
NSString *location = storeFields[#"address"];
NSString *userNames = storeFields[#"node_title"];
NSString *ampRemoved = [userNames stringByReplacingOccurrencesOfString:#"amp;" withString:#""];
NSString *userBio = storeFields[#"body"];
self.x3 = storeFields[#"x3"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
StoreAnnotation *point2 = [[StoreAnnotation alloc] init];
point2.coordinate = placemark.coordinate;
point2.title = ampRemoved;
point2.subtitle = userBio;
point2.index = index; // Store index here.
[self.mapView addAnnotation:point2];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
/// GRAB ALL PARKS LOCATIONS ///
NSMutableDictionary *viewParams8 = [NSMutableDictionary new];
[viewParams8 setValue:#"parks" forKey:#"view_name"];
[DIOSView viewGet:viewParams8 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.parksData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *parkFields in self.parksData) {
// NSLog(#"WHAT IS IN FRIENDS %#", self.friendData);
NSString *location = parkFields[#"address"];
NSString *userNames = parkFields[#"node_title"];
NSString *ampRemoved = [userNames stringByReplacingOccurrencesOfString:#"amp;" withString:#""];
NSString *userBio = parkFields[#"body"];
self.x3 = parkFields[#"x3"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
ParksAnnotation *point3 = [[ParksAnnotation alloc] init];
point3.coordinate = placemark.coordinate;
point3.title = ampRemoved;
point3.subtitle = userBio;
point3.index = index; // Store index here.
[self.mapView addAnnotation:point3];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.5;
mapRegion.span.longitudeDelta = 0.5;
[mapView setRegion:mapRegion animated: YES];
[self.locationManager stopUpdatingLocation];
self.locationManager = nil;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 8000, 8000);
[mapView setRegion:[mapView regionThatFits:region] animated:YES];
[mapView addAnnotations:[mapView annotations]];
});
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if([annotation isKindOfClass:[StoreAnnotation class]]) {
static NSString *identifier = #"stores";
MKAnnotationView *storesView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(storesView == nil) {
storesView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
storesView.displayPriority = MKFeatureDisplayPriorityRequired;
storesView.canShowCallout = YES;
storesView.image = [UIImage imageNamed:#"storeann4.png"];
}
else {
storesView.annotation = annotation;
}
return storesView;
}
if([annotation isKindOfClass:[meetupAnn class]]) {
static NSString *identifier = #"meetUps";
MKAnnotationView *pulsingView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(pulsingView == nil) {
pulsingView.displayPriority = MKFeatureDisplayPriorityRequired;
pulsingView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pulsingView.image = [UIImage imageNamed:#"meetupbeacon.png"];
pulsingView.canShowCallout = YES;
}
else {
pulsingView.annotation = annotation;
}
return pulsingView;
}
if([annotation isKindOfClass:[ParksAnnotation class]]) {
static NSString *identifier = #"parks";
MKAnnotationView *parksView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(parksView == nil) {
parksView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
parksView.displayPriority = MKFeatureDisplayPriorityRequired;
parksView.image = [UIImage imageNamed:#"parksann.png"];
parksView.canShowCallout = YES;
}
else {
parksView.annotation = annotation;
}
return parksView;
}
if([annotation isKindOfClass:[RestAnnotation class]]) {
static NSString *identifier = #"rests";
MKAnnotationView *restView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(restView == nil) {
restView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
restView.displayPriority = MKFeatureDisplayPriorityRequired;
restView.image = [UIImage imageNamed:#"restann.png"];
restView.canShowCallout = YES;
}
else {
restView.annotation = annotation;
}
return restView;
}
As Ramis said, the problem is that you're setting the displayPriority before you even instantiate the pulsingView. Thus, the MKAnnotationView you subsequently instantiate never got its displayPriority set.
That having been said, I'd suggest a slightly different implementation, though. Specifically, I'd move the configuration of the annotation view into its own subclass, rather than cluttering the view controller with this sort of code:
#interface MeetUpAnnotationView: MKAnnotationView
#end
#implementation MeetUpAnnotationView
- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self) {
self.displayPriority = MKFeatureDisplayPriorityRequired;
self.canShowCallout = YES;
self.image = [UIImage imageNamed:#"meetupbeacon.png"];
}
return self;
}
- (void)setAnnotation:(id<MKAnnotation>)annotation {
[super setAnnotation:annotation];
self.displayPriority = MKFeatureDisplayPriorityRequired;
}
#end
Then, if targeting iOS 11 or later, your view controller's viewDidLoad should register that subclass.
Now, if this is the only annotation view that you’re showing in iOS 11, you don't need a viewForAnnotation at all and can just register your default annotation view:
[self.mapView registerClass:[MeetUpAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultAnnotationViewReuseIdentifier];
And having registered the annotation view class, you're done. No viewForAnnotation is needed or desired.
The only time you have to implement viewForAnnotation in iOS 11 and later is if you have multiple custom annotation view types on your map. In that case, you'd register them:
[self.mapView registerClass:[MeetUpAnnotationView class] forAnnotationViewWithReuseIdentifier:meetupIdentifier];
[self.mapView registerClass:[SomeOtherAnnotationView class] forAnnotationViewWithReuseIdentifier:someOtherIdentifier];
And then use dequeueReusableAnnotationViewWithIdentifier:forAnnotation: in your viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MeetupAnn class]]) {
return [mapView dequeueReusableAnnotationViewWithIdentifier:meetupIdentifier forAnnotation:annotation];
}
if ([annotation isKindOfClass:[SomeOtherAnnotation class]]) {
return [mapView dequeueReusableAnnotationViewWithIdentifier:someOtherIdentifier forAnnotation:annotation];
}
...
return nil;
}
As you can see, in iOS 11 (especially when you have only one annotation view type), the code is greatly simplified.
But if you need to support older iOS versions, you can't register the identifier and you have to use the older dequeueReusableAnnotationViewWithIdentifier:, but I'd still let the annotation view subclass take care of configuring itself. But, a more subtle problem in your code is that you are not setting the annotation in an else clause, so make sure to do that, e.g.:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MeetupAnn class]]) {
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:meetupIdentifier];
if (!annotationView) {
annotationView = [[MeetUpAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:meetupIdentifier];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
You should check if some of your geocoding requests are failing inconsistently.
CLGeocoder rate limits your requests and if you do too many requests in a short time, you'll receive an error. https://developer.apple.com/documentation/corelocation/clgeocoder/1423509-geocodeaddressstring?language=objc
Check if you are getting any reason for failure inside NSError* error inside the completionHandler block.
As many times as it fails, you should see as many less number of annotations on the MapView because it is not entering the following code path.
if (placemarks && placemarks.count > 0) {
// Not entering here
}
if (nil != error) {
// Could land here
}
The only other reason would be not properly calculating map region to show all annotations in screen. Make sure you are calculating/adjusting the region correctly upon each annotation being added to the mapView.
// Define these variables globally in the view controller
CLLocationDegrees minLatitude = 90.0;
CLLocationDegrees maxLatitude = -90.0;
CLLocationDegrees minLongitude = 180.0;
CLLocationDegrees maxLongitude = -180.0;
// Call following method every time a new annotation needs to be added to the mapView
-(void)addAnnotation:(id<MKAnnotation>)annotation toMapView:(MKMapView*)mapView {
// Add the annotation to map
[mapView addAnnotation:annotation];
// Set the map region to make it visible along with all other annotations
CLLocationDegrees latitude = annotation.coordinate.latitude;
CLLocationDegrees longitude = annotation.coordinate.longitude;
minLatitude = min(minLatitude, latitude);
maxLatitude = max(maxLatitude, latitude);
minLongitude = min(minLongitude, longitude);
maxLongitude = max(maxLongitude, longitude);
CLLocationDegrees latitudeDelta = (maxLatitude - minLatitude);
CLLocationDegrees longitudeDelta = (maxLongitude - minLongitude);
CLLocationDegrees midLatitude = (maxLatitude - latitudeDelta/2);
CLLocationDegrees midLongitude = (maxLongitude - longitudeDelta/2);
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(midLatitude, midLongitude);
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
if (CLLocationCoordinate2DIsValid(center)) {
[mapView setRegion:region animated:YES];
}
}
You are assigning MKFeatureDisplayPriorityRequired to empty object. Try to assign display priority in two case:
When pulsingView is not nil.
After pulsingView allocated.
if([annotation isKindOfClass:[meetupAnn class]]) {
static NSString *identifier = #"currentLocation";
MKAnnotationView *pulsingView = (MKAnnotationView *)[self.friendsMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(pulsingView == nil) {
pulsingView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pulsingView.displayPriority = MKFeatureDisplayPriorityRequired;
pulsingView.canShowCallout = YES;
pulsingView.image = [UIImage imageNamed:#"meetupbeacon.png"];
NSLog(#"Location Returned");
} else {
pulsingView.displayPriority = MKFeatureDisplayPriorityRequired;
// TODO: Do map pin initial setup.
}
}

exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'

usually this code has worked perfectly for me, up until recently I went to update my project to support the latest iOS and when clicking on the map button, receive the error;
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'
Prior to using Xcode 9 it would work correctly, so I am guessing the way the code works is slightly different now.
The array is NSArray *arr_OfCountryCode;
And we initialise it in the viewDidLoad
//Initialize NSArray object with Images
arr_OfCountryCode=#[#"AF",#"AL",#"DZ",#"AS",#"AD",#"AO",#"AI",#"AQ",#"AG",#"AR",#"AM",#"AW",#"AC",#"AU",#"AT",#"AZ",#"BS",#"BH",#"BD",#"BB",#"BY",#"BE",#"BZ",#"BJ",#"BM",#"BT",#"BO",#"BA",#"BW",#"BV",#"BR",#"IO",#"VG",#"BN",#"BG",#"BF",#"BI",#"KH",#"CM",#"CA",#"IC",#",CV",#"BQ",#"KY",#"CF",#"EA",#"TD",#"CL",#"CN",#"CX",#"CP",#"CC",#"CO",#"KM",#"CD",#"CG",#"CK",#"CR",#"HR",#"CU",#"CW",#"CY",#"CZ",#"CI",#"DK",#"DG",#"DJ",#"DM",#"DO",#"EC",#"EG",#"SV",#"GQ",#"ER",#"EE",#"ET",#"FK",#"FO",#"FJ",#"FI",#"FR",#"FG",#"PF",#"TF",#"GA",#"GM",#"GE",#"DE",#"GH",#"GI",#"GR",#"GL",#"GD",#"GP",#"GU",#"GT",#"GG",#"GN",#"GW",#"GY",#"HT",#"HM",#"HN",#"HK",#"HU",#"IS",#"IN",#"ID",#"IR",#"IQ",#"IE",#"IM",#"IL",#"IT",#"JM",#"JP",#"JE",#"JO",#"KZ",#"KE",#"KI",#"XK",#"KW",#"KG",#"LA",#"LV",#"LB",#"LS",#"LR",#"LY",#"LI",#"LT",#"LU",#"MO",#"MK",#"MG",#"MW",#"MY",#"MV",#"ML",#"MT",#"MH",#"MQ",#"MR",#"MU",#"YT",#"MX",#"FM",#"MD",#"MC",#"MN",#"ME",#"MS",#"MA",#"MZ",#"MM",#"NA",#"NR",#"NP",#"NL",#"NC",#"NZ",#"NI",#"NE",#"NG",#"NU",#"NF",#"KP",#"MP",#"NO",#"OM",#"PK",#"PW",#"PS",#"PA",#"PG",#"PY",#"PE",#"PH",#"PN",#"PL",#"PT",#"PR",#"QA",#"RO",#"RU",#"RW",#"RE",#"WS",#"SM",#"SA",#"SN",#"RS",#"SC",#"SL",#"SG",#"SX",#"SK",#"SI",#"SB",#"SO",#"ZA",#"GS",#"KR",#"SS",#"ES",#"LK",#"BL",#"SH",#"KN",#"LC",#"MF",#"PM",#"VC",#"SD",#"SR",#"SJ",#"SZ",#"SE",#"CH",#"SY",#"ST",#"TW",#"TJ",#"TZ",#"TH",#"TL",#"TG",#"TK",#"TO",#"TT",#"TA",#"TN",#"TR",#"TM",#"TC",#"TV",#"UM",#"VI",#"UG",#"UA",#"AE",#"GB",#"US",#"UY",#"UZ",#"VU",#"VA",#"VE",#"VN",#"WF",#"EH",#"YE",#"ZM",#"ZW",#"AX"];
When the user taps the button, a location on the map is shown at random, within the actionMethod to do that is;
str_Type = #"Randum";
self.mapView.hidden = NO;
int randomIndex = arc4random() % [arr_OfCountryCode count];
NSString *urlString = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=false",[arr_OfCountryCode objectAtIndex:randomIndex]];
NSURL *url = [[NSURL alloc] initWithString:urlString];
I am struggling as to why the array is classed as empty when it worked for multiple iOS versions and devices prior to the latest.
It is showing as nil as soon as I check it in Xcode, other arrays initialise before it with no issue, I even tried copying an existing array, renaming it to *arr_OfCountryCode; and that still showed as nil !
In this method (entire posted below) I believe the problem is occuring.
- (IBAction)actionMethod:(UIButton *)sender {
if ([sender tag] == 0) {
self.musicView.hidden = NO;
[self.tbl_MusicTable reloadData];
} else if ([sender tag] == 1) {
str_Type = #"Randum";
self.mapView.hidden = NO;
int randomIndex = arc4random() % [arr_OfCountryCode count];
NSString *urlString = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=false",[arr_OfCountryCode objectAtIndex:randomIndex]];
NSURL *url = [[NSURL alloc] initWithString:urlString];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc] initWithURL:url] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"%#",error.description);
} else {
NSDictionary *jsonObject=[NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableLeaves
error:nil];
NSDictionary *places = [[[[jsonObject objectForKey:#"results"] objectAtIndex:0] objectForKey:#"geometry"] objectForKey:#"location"];
NSDictionary *locations = [[[jsonObject objectForKey:#"results"] objectAtIndex:0] objectForKey:#"address_components"];
float lat = [[places objectForKey:#"lat"] floatValue];
float lon = [[places objectForKey:#"lng"] floatValue];
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.50;
span.longitudeDelta = 0.50;
location.latitude = lat;
location.longitude = lon;
region.span = span;
region.center = location;
[self.mk_MapView setRegion:region animated:YES];
NSString *str_Title = [[locations valueForKey:#"long_name"] objectAtIndex:0];
NSString *str_Short = [[locations valueForKey:#"short_name"] objectAtIndex:0];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = location;
point.title = str_Title;
point.subtitle = str_Short;
[self.mk_MapView addAnnotation:point];
}
}];
}
}
The further code for corelocation is here
#pragma mark - CLLocationManager Delegate Method
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([str_Type isEqualToString:#"Custom"]) {
CLLocation *currentLocation = newLocation;
NSString *str_Longitude;
NSString *str_Latitude;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.020;
span.longitudeDelta = 0.020;
location.latitude = currentLocation.coordinate.latitude;
location.longitude = currentLocation.coordinate.longitude;
region.span = span;
region.center = location;
[self.mk_MapView setRegion:region animated:YES];
if (currentLocation != nil) {
str_Longitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
str_Latitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
// Reverse Geocoding
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = currentLocation.coordinate;
point.title = placemark.country;
point.subtitle = placemark.locality;
[self.mk_MapView addAnnotation:point];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
} else {
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = location;
point.title = placemark.country;
point.subtitle = placemark.locality;
[self.mk_MapView addAnnotation:point];
}
}
#pragma mark - MKMapView Delegate Methods
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
if(annotation != self.mk_MapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKAnnotationView *)[self.mk_MapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
//pinView.pinColor = MKPinAnnotationColorGreen;
pinView.canShowCallout = YES;
//pinView.animatesDrop = YES;
pinView.image = [UIImage imageNamed:#"HesOnThisMap"]; //
}
else {
//[self.mk_MapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKAnnotationView *aV;
for (aV in views) {
CGRect endFrame = aV.frame;
aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - 230.0, aV.frame.size.width, aV.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.45];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[aV setFrame:endFrame];
[UIView commitAnimations];
}
}
It was to do with the google maps api callbacks, it was crashing when it hit the maximum callbacks

MapView: Tapping annotation gives me wrong detail view data?

I'm using an NSDictionary to populate data for my MapView annotations. However, when I tap on my MapView annotation, the detailView should display the selected user's information. That said, right now, when I tap an annotation, all detailViews display the same user's information (even though the details in the actual annotation's display bubble are correct). How can I fix this? Why won't NSDictionary allow me to do this?
MapViewController.m
NSMutableDictionary *viewParams = [NSMutableDictionary new];
[viewParams setValue:#"u000" forKey:#"view_name"];
[DIOSView viewGet:viewParams success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.addressData = [responseObject mutableCopy];
for (NSMutableDictionary *multiplelocations in self.addressData) {
NSString *location = multiplelocations[#"street_address"];
NSLog(#"Pull addresses %#", location);
NSString *userNames = multiplelocations[#"users_name"];
NSString *userBio = multiplelocations[#"userbio"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = placemark.coordinate;
point.title = userNames;
point.subtitle = userBio;
[self.mapView addAnnotation:point];
}
}
];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
-(void)calloutTapped:(UITapGestureRecognizer *) sender
{
NSLog(#"Callout was tapped");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
OtherUserViewController *yourViewController = (OtherUserViewController *)[storyboard instantiateViewControllerWithIdentifier:#"OtherUserViewController"];
NSDictionary *dictionary = [[NSDictionary alloc] init];
dictionary = [[self.addressData firstObject] mutableCopy];
yourViewController.mapuserData = dictionary;
[self.navigationController pushViewController:yourViewController animated:YES];
}
self.addressData via console
{
address = "1300 Fake Street, Vancouver, BC";
childrenunder = No;
city = Va;
"emergency facility" = Yes;
"first name" = Admin;
"last name" = Account;
phone = "Not Available";
"photo_path" = "http://myurl.com/files/stored/1461176121.jpg";
"postal code" = V6B0L1;
"profile photo" = "<img typeof=\"foaf:Image\" src=\"stored/1461176121.jpg\" width=\"300\" height=\"300\" alt=\"\" />";
"property type" = House;
province = B;
"street_address" = "1300 Fake Street, Vancouver, BC";
supervision = Yes;
uid = 1;
userbio = "Need assistance? This account belongs to the team! Message us if you have any questions.";
"users_name" = Britt;
}
)
dictionary = [[self.addressData firstObject] mutableCopy];
Are you serious?
This should be
NSMutableDictionary *dictionary = [self.addressData mutableCopy];
While navigating to detail view controller, you are always getting the first object from the dictionary array.
[[self.addressData firstObject] mutableCopy];
Thats the reason you are getting the same information for all the annotation view.
Instead of that line of code, You have to identify which map marker is clicked on the MapView, for example identify the index of the dictionary array. Pick the dictionary from the array and pass it to the detail view.

How to add image in annotation in mkmap [duplicate]

This question already has answers here:
How to use custom icons with mapKit framework?
(2 answers)
Closed 8 years ago.
I am new to Xcode, i need to set the image in annotation point. I am trying to replace the typical iOS mapkit "pin" with a particular image. I'm new to coding so I'm not sure exactly why this isn't working, but here is what i've attempted
My code is
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *urlMapString=[NSString stringWithFormat:#"http://www.xxxx.com/xxxx_webservice/map.php?format=json&truckno=%#",nam2];
NSURL *urlMap=[NSURL URLWithString:urlMapString];
NSData *dataMap=[NSData dataWithContentsOfURL:urlMap];
NSError *errorMap;
NSDictionary *jsonMap = [NSJSONSerialization JSONObjectWithData:dataMap options:kNilOptions error:&errorMap]; NSArray *resultsMap = [jsonMap valueForKey:#"posts"];
NSArray *resMap = [resultsMap valueForKey:#"post"];
NSArray *latitudeString=[resMap valueForKey:#"latitude"];
NSString *latOrgstring = [latitudeString objectAtIndex:0];
double latitude=[latOrgstring doubleValue];
NSArray *longitudeString=[resMap valueForKey:#"longitude"];
NSString *longOrgstring = [longitudeString objectAtIndex:0];
double longitude=[longOrgstring doubleValue];
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
//Span
MKCoordinateSpan span;
span.latitudeDelta=THE_SPAN;
span.longitudeDelta=THE_SPAN;
myRegion.center=center;
myRegion.span=span;
//Set our mapView
[MapViewC setRegion:myRegion animated:YES];
//Annotation
//1.create coordinate for use with the annotation
CLLocationCoordinate2D wimbLocation;
wimbLocation.latitude=latitude;
wimbLocation.longitude=longitude;
Annotation * myAnnotation= [Annotation alloc];
myAnnotation.image = [UIImage imageNamed:#"icon.gif"];
CLLocation *someLocation=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:someLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSDictionary *dictionary = [[placemarks objectAtIndex:0] addressDictionary];
addressOutlet=[dictionary valueForKey:#"Street"];
City=[dictionary valueForKey:#"City"];
State=[dictionary valueForKey:#"State"];
myAnnotation.coordinate=wimbLocation;
if (addressOutlet!=NULL&&City!=NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
myAnnotation.image = [UIImage imageNamed:#"icon.gif"];
}
else if (addressOutlet==NULL&&City!=NULL)
{
myAnnotation.title=City;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#,%#", City, State];
myAnnotation.image = [UIImage imageNamed:#"icon.gif"];
}
else if (addressOutlet!=NULL&&City==NULL)
{
myAnnotation.title=addressOutlet;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#", State];
myAnnotation.image = [UIImage imageNamed:#"icon.gif"];
}
else if(addressOutlet==NULL&&City==NULL)
{
myAnnotation.title=State;
myAnnotation.subtitle=[NSString stringWithFormat:#"%#",State];
myAnnotation.image = [UIImage imageNamed:#"icon.gif"];
}
[self.MapViewC addAnnotation:myAnnotation];
}];
}
Please guide me to set the image..
Thanks in Advance
You can use mapView Delegate method.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation)
return nil;
static NSString *s = #"identifier";
MKAnnotationView *pin = [mapView dequeueReusableAnnotationViewWithIdentifier:s];
if (!pin) {
pin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:s];
pin.canShowCallout = YES;
pin.image = [UIImage imageNamed:#"pin.png"];
pin.calloutOffset = CGPointMake(0, 0);
}
return pin;
}

how to link static cells to Outlet/Actions - E.G tap the call cell to call the number

The code I have. By the way, I can't get Call to work and Website does not open either!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *urlToOpen = #"";
if( indexPath.section == 0 ){
// call number
urlToOpen = #"tel:442074036933";
} else if( indexPath.section == 1 ){
// open website
urlToOpen = #"http://www.designmuseum.org";
} else {
// open address
urlToOpen = #"http://maps.apple.com/maps?daddr=Design+Museum+London";
}
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlToOpen]];
NSString *destinationAddress = [NSString stringWithFormat:#"%#+%#+%#",
[address street],
[address city],
[address country]];
NSString *sourceAddress = [LocalizedCurrentLocation currentLocationStringForCurrentLanguage];
NSString *url = [NSString stringWithFormat:#"http://maps.apple.com/maps?saddr=%#&daddr=%#",
[sourceAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[destinationAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
I need to add destination address which for my App is = 28 Shad Thames, London, United Kingdom. Which format to write it in? because I cant get it to work and really need to sort this problem of my app real quick
You don't need to create outlets for each cell.
Is your didSelectRowAtIndexPath method called?
Then you could just do:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *urlToOpen = #"";
if( indexPath.section == 0 ){
// call number
urlToOpen = #"tel:12125551212";
} else if( indexPath.section == 1 ){
// open website
urlToOpen = #"http://www.google.nl";
} else {
// open address
NSString *destinationAddress = #"Amsterdam";
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:destinationAddress completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count] > 0) {
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithPlacemark:[placemarks objectAtIndex:0]];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:placeMark];
MKMapItem *mapItem2 = [MKMapItem mapItemForCurrentLocation];
NSArray *mapItems = #[mapItem, mapItem2];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeStandard],
MKLaunchOptionsShowsTrafficKey:#YES
};
[MKMapItem openMapsWithItems:mapItems launchOptions:options];
} else {
//error nothing found
}
}];
return;
} else {
NSString *sourceAddress = [LocalizedCurrentLocation currentLocationStringForCurrentLanguage];
urlToOpen = [NSString stringWithFormat:#"http://maps.google.com/maps?saddr=%#&daddr=%#",
[sourceAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[destinationAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
}
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlToOpen]];
}
indexPath.section could also be indexPath.row, depending on how you made the tableView.
Edit:
I have added the 'Get Directions' part. This checks if it is ios5 or ios6.
For ios5 I use the LocalizedCurrentLocation from this post http://www.martip.net/blog/localized-current-location-string-for-iphone-apps
For ios6 I use the CLGeocoder to get the placemark and then open the map with it and the current location.
Remember to add CoreLocation.framework and MapKit.framework

Resources