Importing NSMutable Array into Map Annotations - annotations

Hi all i have a mysql database that consists of 7 columns and i have a script that reads it and extracts the data as JSON which i have pulled into an NSMutableArray, I want to be able to use this array to setup annotations on my Map but i'm not sure what to do here, as you can see i have defined one annotation here which shows up no problem but i'm honestly not sure how to show the NSMutableArray items? The NSMutable array will have more information than needed for the Annotations, I only need, coordinate, title and subtitle so how can i go about doing this? Here is my code so far:
hazards.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Hazards : NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, strong) NSString * ID;
#property (nonatomic, strong) NSString * ROUTE;
#property (nonatomic, strong) NSString * ADDRESS;
#property (nonatomic, strong) NSString * LATITUDE;
#property (nonatomic, strong) NSString * LONGITUDE;
#property (nonatomic, strong) NSString * HAZARD;
#property (nonatomic, strong) NSString * RISK;
// Methods
- (id) initWithID: (NSString *) hazardsID andROUTE: (NSString *) hazardsROUTE andADDRESS: (NSString *) hazardsADDRESS andLATITUDE: (NSString *) hazardsLATITUDE andLONGITUDE: (NSString *) hazardsLONGITUDE andHAZARD: (NSString *) hazardsHAZARD andRISK: (NSString *) hazardsRISK;
#end
hazards.m
#import "Hazards.h"
#implementation Hazards
#synthesize coordinate, title, subtitle, ID, ROUTE, ADDRESS, LATITUDE, LONGITUDE, HAZARD, RISK;
- (id) initWithID: (NSString *) hazardsID andROUTE: (NSString *) hazardsROUTE andADDRESS: (NSString *) hazardsADDRESS andLATITUDE: (NSString *) hazardsLATITUDE andLONGITUDE: (NSString *) hazardsLONGITUDE andHAZARD: (NSString *) hazardsHAZARD andRISK: (NSString *) hazardsRISK {
self = [super init];
if (self)
{
ID = hazardsID;
ROUTE = hazardsROUTE;
ADDRESS = hazardsADDRESS;
LATITUDE = hazardsLATITUDE;
LONGITUDE = hazardsLONGITUDE;
HAZARD = hazardsHAZARD;
RISK = hazardsRISK;
}
return self;
}
#end
viewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "Hazards.h"
#interface ViewController : UIViewController
#property (nonatomic, strong) NSMutableArray *json;
#property (nonatomic, strong) NSMutableArray *hazardsArray;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#pragma mark - Methods
-(void) retrieveData;
#end
viewController.m
#import "ViewController.h"
#import "Hazards.h"
#interface ViewController ()
#end
// Railway Street Ballymena Coordinates
#define BALLYMENA_LATITUDE 54.857719;
#define BALLYMENA_LONGITUDE -6.280654;
// Span
#define THE_SPAN 0.01f;
#define getDataURL #"localhost:8888/rmb/json.php"
#implementation ViewController
#synthesize json, hazardsArray, mapView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Create the region
MKCoordinateRegion myRegion;
// Center
CLLocationCoordinate2D center;
center.latitude = BALLYMENA_LATITUDE;
center.longitude = BALLYMENA_LONGITUDE;
//Span
MKCoordinateSpan span;
span.latitudeDelta = THE_SPAN;
span.longitudeDelta = THE_SPAN;
myRegion.center = center;
myRegion.span = span;
// Set our mapview
[mapView setRegion:myRegion animated: YES];
// Annotation
NSMutableArray *locations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location;
Hazards *myAnn;
// Pin to show Royal Mail Ballymena delivery office
myAnn = [[Hazards alloc] init];
location.latitude = BALLYMENA_LATITUDE;
location.longitude = BALLYMENA_LONGITUDE;
myAnn.coordinate = location;
myAnn.title = #"Royal Mail Ballymena";
myAnn.subtitle = #"111, Railway Street";
[locations addObject:myAnn];
[self.mapView addAnnotations:locations];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Methods
-(void) retrieveData {
NSURL *url = [NSURL URLWithString:getDataURL];
NSData *data = [NSData dataWithContentsOfURL:url];
json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
// Setup our hazards array
hazardsArray = [[NSMutableArray alloc] init];
for (int i =0; i < json.count; i++) {
// Create hazard object
NSString *hazardsID = [[json objectAtIndex:i] objectForKey:#"ID"];
NSString *hazardsROUTE = [[json objectAtIndex:i] objectForKey:#"ROUTE"];
NSString *hazardsADDRESS = [[json objectAtIndex:i] objectForKey:#"ADDRESS"];
NSString *hazardsLATITUDE = [[json objectAtIndex:i] objectForKey:#"LATITUDE"];
NSString *hazardsLONGITUDE = [[json objectAtIndex:i] objectForKey:#"LONGITUDE"];
NSString *hazardsHAZARD = [[json objectAtIndex:i] objectForKey:#"HAZARD"];
NSString *hazardsRISK = [[json objectAtIndex:i] objectForKey:#"RISK"];
Hazards *myHazards = [[Hazards alloc] initWithID:hazardsID andROUTE:hazardsROUTE andADDRESS:hazardsADDRESS andLATITUDE:hazardsLATITUDE andLONGITUDE:hazardsLONGITUDE andHAZARD:hazardsHAZARD andRISK:hazardsRISK];
// Add our hazards object to our hazards array
[hazardsArray addObject:myHazards];
}
// [self.mapView addAnnotation:hazardsArray];
}
#end
Many Thanks in Advance

Assuming your retrieveData correctly builds Hazard objects and is called at the right time you could either add them one at a time with this line inside the loop
[self.mapView addAnnotation:myHazards];
or all at once after the loop is finished
[self.mapView addAnnotations:hazardsArray];

Related

How to extend MKPointAnnotation and add a property to it

I'm trying to extend MKPointAnnotation and add a property to for an NSString called dealLink.
I thought I set it up correctly, but I'm getting this error at the moment:
Property 'dealLink' not found on object of type 'MKPointAnnotation *'
Here's my code in a view controller called MapOffersViewController.m:
#pragma mark - Populate Map
- (void)populateMap:(MKMapView*)map withDeals:(NSArray*) deals
{
NSLog(#"Deals " );
for (NSDictionary *currentDeal in deals) {
CLLocationCoordinate2D ctrpoint;
ctrpoint.latitude = [[[currentDeal objectForKey:#"coords"] objectForKey:#"lat"] doubleValue];
ctrpoint.longitude =[[[currentDeal objectForKey:#"coords"] objectForKey:#"lng"] doubleValue];
MKPointAnnotation *dealAnnotation = [[MKPointAnnotation alloc] init];
dealAnnotation.coordinate = ctrpoint;
dealAnnotation.title = [currentDeal objectForKey:#"vendor"];
**dealAnnotation.dealLink = [currentDeal objectForKey:#"link"];**
NSDictionary *currDict = #{
#"EUR": #"€",
#"GBP": #"₤",
#"USD": #"$",
#"BRL": #"R$"
};
NSString *currName = [currentDeal objectForKey:#"currency"];
NSString *currency = [currDict objectForKey:currName];
dealAnnotation.subtitle = [NSString stringWithFormat:#"%#%i",currency,[[currentDeal objectForKey:#"price"] integerValue ]];
NSLog(#"current deal id is %#",[currentDeal objectForKey:#"id"]);
[map setDelegate:self];
[map addAnnotation:dealAnnotation];
}
}
I'm importing this class called MapAnnotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapAnnotation : MKPointAnnotation
{
NSString *title;
NSString *subtitle;
NSString *dealLink;
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, retain) NSString *dealLink;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithTitle:(NSString *)ttl subTitle:(NSString *)subttl dealLink:(NSString *)dealLnk andCoordinate:(CLLocationCoordinate2D)c2d;
#end
and it's .m:
#import "MapAnnotation.h"
#implementation MapAnnotation
#synthesize title,subtitle,dealLink,coordinate;
- (id)initWithTitle:(NSString *)ttl subTitle:(NSString *)subttl dealLink:(NSString *)dealLnk andCoordinate:(CLLocationCoordinate2D)c2d {
title = ttl;
subtitle = subttl;
dealLink = dealLnk;
coordinate = c2d;
return self;
}
#end
thanks for any help
I used Craig's answer below and this additional code to get this working:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
NSLog(#"callout tapped from del method %#", dealUrl);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:dealUrl]];
}
- (void)mapView:(MKMapView *)mapView1 didSelectAnnotationView:(MKAnnotationView *)mapView2
{
MapAnnotation *annotation = mapView2.annotation;
NSString *temp = annotation.dealLink;
dealUrl = temp;
// NSLog(#"temp is %#", temp);
}
You're creating an MKPointAnnotation and trying to access dealLink, which is only on MapAnnotations. You need to create a MapAnnotation
....
ctrpoint.longitude =[[[currentDeal objectForKey:#"coords"] objectForKey:#"lng"] doubleValue];
MapAnnotation *dealAnnotation = [[MapAnnotation alloc] init];
dealAnnotation.coordinate = ctrpoint;
....

Add subtitle to annotation using UICRouteAnnotation

UICRouteAnnotation *startAnnotation = [[UICRouteAnnotation alloc] initWithCoordinate [[routePoints objectAtIndex:0] coordinate]
title:#"Origin"
subtitle:#"Subtitle Here"
annotationType:UICRouteAnnotationTypeStart];
I am trying to add a subtitle to this annotation but don't have much experience with UICRouteAnnotation and was not able to find much documentation on it. Adding "subtitle:" through exceptions.
What am I missing? Why doesn't the subtitle work when doing it like this?
What I didn't realize is that UICRouteAnnotation needed to be modified to accept a subtitle. Here is my updated h and m files for UICRouteAnnotation. Making the below changes fixed my issue so the code I posted in my question works as intended.
Thanks Anna for pointing me in the right direction.
.h file
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
typedef enum UICRouteAnnotationType {
UICRouteAnnotationTypeStart,
UICRouteAnnotationTypeEnd,
UICRouteAnnotationTypeWayPoint,
} UICRouteAnnotationType;
#interface UICRouteAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
UICRouteAnnotationType annotationType;
}
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly, copy) NSString *title;
#property (nonatomic, readonly, copy) NSString *subtitle;
#property (nonatomic) UICRouteAnnotationType annotationType;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord
title:(NSString *)aTitle
subtitle:(NSString *)aSubTitle
annotationType:(UICRouteAnnotationType)type;
#end
.m file
#import "UICRouteAnnotation.h"
#implementation UICRouteAnnotation
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
#synthesize annotationType;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coord
title:(NSString *)aTitle
subtitle:(NSString *)aSubTitle
annotationType:(UICRouteAnnotationType)type {
self = [super init];
if (self != nil) {
coordinate = coord;
title = [aTitle retain];
subtitle = [aSubTitle retain];
annotationType = type;
}
return self;
}
- (void)dealloc {
[title release];
[subtitle release];
[super dealloc];
}
#end

'MyAnnotation' may not respond to 'initWithDictionary:'

I keep getting this semantic issue with this code ('MyAnnotation' may not respond to 'initWithDictionary:'), im adding annotations to a map using a plist.
Even though it displays the pin and everything i want it to, i get an semantic issue and cant seem to solve the problem
if anyone could help that would be great thanks
heres the code, the problem is in the //BrewMapViewController.m the error is on this line
MyAnnotation *annotation = [[MyAnnotation alloc] initWithDictionary:breweryDict];
/*MyAnnotation.h*/
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSString *test;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *test;
#end
/*MyAnnotation.m*/
#import "MyAnnotation.h"
#implementation MyAnnotation
#synthesize coordinate, title, subtitle, test;
- (id) initWithDictionary:(NSDictionary *) dict
{
self = [super init];
if (self != nil) {
coordinate.latitude = [[dict objectForKey:#"latitude"] doubleValue];
coordinate.longitude = [[dict objectForKey:#"longitude"] doubleValue];
self.title = [dict objectForKey:#"name"];
self.subtitle = [dict objectForKey:#"address"];
self.test = [dict objectForKey:#"test"];
}
return self;
}
#end
/*BrewMapViewController.h*/
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface BrewMapViewController : UIViewController <MKMapViewDelegate> {
IBOutlet MKMapView *map;
NSArray *breweries;
}
#end
/*BrewMapViewController.m*/
#import "BrewMapViewController.h"
#import "MyAnnotation.h"
#implementation BrewMapViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
breweries = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"test"
ofType:#"xml"]];
double minLat = [[breweries valueForKeyPath:#"#min.latitude"] doubleValue];
double maxLat = [[breweries valueForKeyPath:#"#max.latitude"] doubleValue];
double minLon = [[breweries valueForKeyPath:#"#min.longitude"] doubleValue];
double maxLon = [[breweries valueForKeyPath:#"#max.longitude"] doubleValue];
MKCoordinateRegion region;
region.center.latitude = (maxLat + minLat) / 2.0;
region.center.longitude = (maxLon + minLon) / 2.0;
region.span.latitudeDelta = (maxLat - minLat) * 1.05;
region.span.longitudeDelta = (maxLon - minLon) * 1.05;
map.region = region;
for (NSDictionary *breweryDict in breweries){
MyAnnotation *annotation = [[MyAnnotation alloc] initWithDictionary:breweryDict];
[map addAnnotation:annotation];
[annotation release];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if (map.userLocation == annotation){
return nil;
}
NSString *identifier = #"MY_IDENTIFIER";
MKAnnotationView *annotationView = [map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil){
annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:identifier]
autorelease];
annotationView.image = [UIImage imageNamed:#"beer.png"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.leftCalloutAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pretzel.png"]] autorelease];
}
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
NSLog(#"I've been tapped");
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc {
[breweries release];
[map release];
[super dealloc];
}
#end
You have to put the method signature for - (id) initWithDictionary:(NSDictionary *) dict into your header file in order to tell BrewMapViewController that the method exists:
/*MyAnnotation.h*/
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
NSString *test;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#property (nonatomic, copy) NSString *test;
- (id) initWithDictionary:(NSDictionary *) dict;
#end

Add random annotations to MKMapView

I need to add 'xx' amout of random annotations to an MKMapView, within a certain range of the user's current location. But i can't figure out how to do it.
Can some of you help me?
Something like this might help:
for(int i=0;i<10;i++) {
CGFloat latDelta = rand()*0.125/RAND_MAX - 0.02;
CGFloat lonDelta = rand()*0.130/RAND_MAX - 0.08;
CLLocationCoordinate2D newCoord = {myLocation.coordinate.latitude+latDelta, myLocation.coordinate.longitude+lonDelta};
DisplayMap *ann = [[DisplayMap alloc] init];
ann.title = #"Some Pin";
ann.subtitle = [NSString stringWithFormat:#"Pin %i subtitle",i+1];
ann.coordinate = newCoord;
[mapView addAnnotation:ann];
[ann release];
}
where:
myLocation is a CLLocation instance.
DisplayMap is:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface DisplayMap : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#end

How to add another annotation in the mapview a certain distance from current location

Wondering how to add another annotation in the mapview a certain distance from current location?
you can use below sample code;
// .h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface AddressAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
MKPinAnnotationColor pinColor;
}
#property (nonatomic,retain) NSString *title;
#property (nonatomic,retain) NSString *subtitle;
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
#end
// .m
#import "AddressAnnotation.h"
#implementation AddressAnnotation
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
#synthesize pinColor;
- (NSString *)subtitle{
return subtitle;
}
- (NSString *)title{
return title;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D) c{
coordinate=c;
return self;
}
#end
currentLocation.latitude = latitudeValue;
currentLocation.longitude = longitudeValue;
AddressAnnotation *addAnnotation = [[AddressAnnotation alloc] initWithCoordinate:currentLocation];
[addAnnotation setTitle:#"Title"];
[addAnnotation setPinColor:MKPinAnnotationColorGreen];
[map addAnnotation:addAnnotation];
[addAnnotation release];
otherLocation.latitude = latitudeValue;
otherLocation.longitude = longitudeValue;
addAnnotation = [[AddressAnnotation alloc] initWithCoordinate:otherLocation];
[addAnnotation setTitle:#"otherTitle"];
[map addAnnotation:addAnnotation];
[addAnnotation release];