Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
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

Code:
#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

Code:
#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

Code:
#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

Code:
#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
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Thanks for the code. Can you explain what isn't working? Are you getting any warnings / errors / run-time crashes? Any other debugging info you can provide us?
 

waterskier2007

macrumors 68000
Jun 19, 2007
1,872
230
Novi, MI
At first glance it appears that the problem is that your Hazards class does not follow the protocol for MKAnnotation. In the documentation here it states that the class must implement the coordinate property. While yours has this as a property, there must be a method that returns this property so that the annotations can be placed on the map

so in your hazards.m you might try something like this

Code:
-(CLLocationCoordinate2D)coordinate
{
     return CLLocationCoordinate2DMake(self.LATITUDE, self.LONGITUDE)
}

You may also want to implement (again in hazards.m) but these are optional
Code:
-(NSString *)title
{
     return self.ADDRESS
}

-(NSString *)subtitle
{
     return self.ID
}


Also, according to the documentation I provided above, the coordinate property should actually be
Code:
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
Thanks for the replies, I'll have a try fixing my code later and if i am still struggling i'll try and explain whats happening.

Thanks Again
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
Another thing I see:

In your retrieveData method you build an array of hazard objects, but then you call addAnnotation instead of addAnnotations

addAnnotation is for adding a single object that conforms to the MKAnnotation protocol. You should be using the method addAnnotations, which takes an array of annotation objects.


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:
 
Last edited by a moderator:

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
I've updated my code with the information provided above but i'm getting an error message:

Passing 'NSString *' to parameter of incompatible type 'CLLocationDegrees' (aka 'double')

I'm not actually sure what this means? Going back to when i created my mysql database my latitude & longitude were stored as double then it was exported to JSON and then imported into my hazardsArray, just incase this has anything to do with the error?

it's the line:

return CLLocationCoordinate2DMake(self.LATITUDE, self.LONGITUDE); that throws up the error

Code:
-(CLLocationCoordinate2D)coordinate
{
    return CLLocationCoordinate2DMake(self.LATITUDE, self.LONGITUDE);
}

-(NSString *)title
{
    return self.HAZARD;
}

-(NSString *)subtitle
{
    return self.ADDRESS;
}

@end
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,567
6,073
Passing 'NSString *' to parameter of incompatible type 'CLLocationDegrees' (aka 'double')

return CLLocationCoordinate2DMake(self.LATITUDE, self.LONGITUDE); that throws up the error.

What type have you declared self.LATITUDE as being in your code? What about self.LONGITUDE? Check Apple's documentation for this type and see if you can find a method that will convert it to a double, which is what the arguments of CLLocationCoordinate2DMake() should be.

(I know the answers and could just give you the code, but I'm trying to teach you how to read the messages Xcode gives you and how to read the relevant documentation to help you solve it.)
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
(I know the answers and could just give you the code, but I'm trying to teach you how to read the messages Xcode gives you and how to read the relevant documentation to help you solve it.)

I totally understand what you're saying here and really appreciate every ones help :) I'll have another attempt and see what i can come up with and if need be i'll come back to you for more hints hehehehe
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
I think i've converted the LATITUDE & LONGITUDE into double's each called dLAT & dLONG but it say's they are unused variables? I thought it was just a matter of adding:

return CLLocationCoordinate2DMake(self.dLAT, self.dLONG);

but that didn't work :( am i close? :confused:

Code:
- (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;
        
        double dLAT = [LATITUDE doubleValue];
        double dLONG = [LONGITUDE doubleValue];
    }
return self;
}


-(CLLocationCoordinate2D)coordinate
{
    return CLLocationCoordinate2DMake(self.dLAT, self.dLONG);
}

-(NSString *)title
{
    return self.HAZARD;
}

-(NSString *)subtitle
{
    return self.ADDRESS;
}

@end
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Your problem is misunderstanding scoping. "self." references properties not local variables, especially not those from other methods. Your double dLAT and double dLONG are declared in your initWithID:. What would you say happens to them after your initWithID: finishes running?
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
Your problem is misunderstanding scoping. "self." references properties not local variables, especially not those from other methods. Your double dLAT and double dLONG are declared in your initWithID:. What would you say happens to them after your initWithID: finishes running?

By the way, as a general rule, using a string to store a double-precision floating point value is a bad idea. Double precision floats have like 18 decimal digits of precision, and string representations of numbers are usually limited to a handful of decimal digits.

lat/long values need double precision to be placed accurately on the map.

I would STRONGLY suggest that you change your custom annotation class to save it's lat/long pairs internally as doubles. If you are setting them from JSON data, convert the incoming strings to doubles and set the annotations values that way. Don't degrade your internal data types because your source data uses a less-than-ideal data format.
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
By the way, as a general rule, using a string to store a double-precision floating point value is a bad idea. Double precision floats have like 18 decimal digits of precision, and string representations of numbers are usually limited to a handful of decimal digits.

While I agree with your general point, strings should be less restrictive than doubles in the number of digits they could store, correct? Why would they be "usually limited"?
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
While I agree with your general point, strings should be less restrictive than doubles in the number of digits they could store, correct? Why would they be "usually limited"?


It boils down to how the format strings are defined and handled.

The standard

Code:
NSString *aString = [NSString stringWithFormat: @"%f", doubleValue];
Will only output a few decimal places.

granted, you can use

Code:
NSString *aString = [NSString stringWithFormat: @"%.18f", doubleValue];

Instead.

Another issue is that native floating point data types like double and float do not correspond directly with their decimal equivalents.

The value 0.1 (1/10) is a repeating "decimal" in binary, just like 1/3 is a repeating decimal, .3333333... in decimal notation.
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,567
6,073
It boils down to how the format strings are defined and handled.

The standard

Code:
NSString *aString = [NSString stringWithFormat: @"%f", doubleValue];
Will only output a few decimal places.

granted, you can use

Code:
NSString *aString = [NSString stringWithFormat: @"%.18f", doubleValue];

Instead.

Another issue is that native floating point data types like double and float do not correspond directly with their decimal equivalents.

The value 0.1 (1/10) is a repeating "decimal" in binary, just like 1/3 is a repeating decimal, .3333333... in decimal notation.

The data is received in JSON, which means its going to be a string at some point no matter what, right? JSON is never anything besides plain text, am I right? Therefore, there's no option there.

The data needs to be a double in the end for it to work with the maps API. Therefore there's no option there, either. There's no way to improve on this system. The data is received as a string and must be changed to a double before it can be used.
 

Duncan C

macrumors 6502a
Jan 21, 2008
853
0
Northern Virginia
The data is received in JSON, which means its going to be a string at some point no matter what, right? JSON is never anything besides plain text, am I right? Therefore, there's no option there.

The data needs to be a double in the end for it to work with the maps API. Therefore there's no option there, either. There's no way to improve on this system. The data is received as a string and must be changed to a double before it can be used.


True. My point is that the native format for Apple's annotations is doubles. Better to convert the JSON data to Apple's native format than to store it in the input format.
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
So is there a chance that when I change the data I imported from JSON into a NSMutableArray and then into a double could have changed knocking out my coordinates accuracy?

I'm still unsure how to edit my code to fix this error anyway and some advice would be much appreciated as i was hoping to have the Annotations up and running today
 
Last edited:

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
So is there a chance that when I change the data I imported from JSON into a NSMutableArray and then into a double could have changed knocking out my coordinates accuracy?

There's a chance. But if you're using NSString's doubleValue method, you should be okay.

I'm still unsure how to edit my code to fix this error anyway and some advice would be much appreciated as i was hoping to have the Annotations up and running today
What error, again? Did you fix your scoping issue yet?
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
There's a chance. But if you're using NSString's doubleValue method, you should be okay.


What error, again? Did you fix your scoping issue yet?

Dejo I'd be more than happy to zip my project and email it to you if you didn't mind? I don't think there's too much wrong it's just me new to programming and I'm confusing myself :)
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Dejo I'd be more than happy to zip my project and email it to you if you didn't mind?

Sorry, but I kind of do mind. I'm here, along with plenty of others, to provide guidance in a community setting. I'm afraid I can't be doing one-on-one development consultation.

I don't think there's too much wrong it's just me new to programming and I'm confusing myself :)

What warnings/errors are you getting?
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
Sorry, but I kind of do mind. I'm here, along with plenty of others, to provide guidance in a community setting. I'm afraid I can't be doing one-on-one development consultation.



What warnings/errors are you getting?

No problem I understand :)

I'm just collecting my daughter from school so I'll post the errors as soon as I can.

I appreciate all the help thanks
 

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
Ok so here's the code that's giving me error messages, i know you've mentioned i need to convert my Latitude & Longitude NSString's to doubles but i'm really not sure how to implement this? Here's the section of code that needs looked at, Sorry for being a pain :eek:

Code:
#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;
}

  // Not sure how this code needs to be changed to make the
  // NSStrings LATITUDE & LONGITUDE turn into doubles

NSString *aString = [NSString stringWithFormat: @"%f", doubleValue];

-(CLLocationCoordinate2D)coordinate
{
    return CLLocationCoordinate2DMake(self.LATITUDE, self.LONGITUDE);
}

-(NSString *)title
{
    return self.HAZARD;
}

-(NSString *)subtitle
{
    return self.ADDRESS;
}

@end

Error Messages:

Code:
NSString *aString = [NSString stringWithFormat: @"%f", doubleValue];
Use of undeclared identifier 'doubleValue'

Code:
return CLLocationCoordinate2DMake(self.LATITUDE, self.LONGITUDE);
Passing 'NSString *' to parameter of incompatible type 'CLLocationDegrees' (aka 'double')
 
Last edited:

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
Well, putting code (your aString assignment) outside of a method is probably not what you intended.

But, let's take a step back. Remove that line and comment out your coordinate method. As per Duncan C's suggestion, let's make your latitude and longitude (notice the case follows common Cocoa coding guidelines; appropriate adjustments to all other UPPER-CASED variables should be made as well) properties more appropriate types:
Code:
@property (nonatomic, assign) CLLocationDegrees latitude;
@property (nonatomic, assign) CLLocationDegrees longitude;

You'll then want to convert the lat/long strings that come in as parameters in your initWithID:. Any guesses as to how?
 
Last edited:

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
Well, putting code (your aString assignment) outside of a method is probably not what you intended.

But, let's take a step back. Remove that line and comment out your coordinate method. As per Duncan C's suggestion, let's make your latitude and longitude (notice the case follows common Cocoa coding guidelines; appropriate adjustments to all other UPPER-CASED variables should be made as well) properties more appropriate types:
Code:
@property (nonatomic, assign) CLLocationDegrees latitude;
@property (nonatomic, assign) CLLocationDegrees longitude;

You'll then want to convert the lat/long strings that come in as parameters in your initWithID:. Any guesses as to how?


An ABSOLUTE Guess :eek::eek::eek:

Code:
-(id) initWithLatitude: (double *) dLat  andLong: (double *) dLong;
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
An ABSOLUTE Guess :eek::eek::eek:

Code:
-(id) initWithLatitude: (double *) dLat  andLong: (double *) dLong;

I would leave your definition of initWithID:... alone (other than fixing the camel-case issue), since it's using the values pulled from your JSON. Instead I would convert the strings to double when doing the assignment within the method. And, remember, NSString has a doubleValue method (that you've seen before) to help with this.

So, willing to propose what those two assignment lines would look like? Can you fill-in the blanks?

Code:
latitude = _____; // convert the string hazardsLatitude to a double here
longitude = _____; // convert the string hazardsLongitude to a double here
 
Last edited:

Futhark

macrumors 65816
Original poster
Jun 12, 2011
1,238
179
Northern Ireland
I would leave your definition of initWithID:... alone (other than fixing the camel-case issue), since it's using the values pulled from your JSON. Instead I would convert the strings to double when doing the assignment within the method. And, remember, NSString has a doubleValue method (that you've seen before) to help with this.

So, willing to propose what those two assignment lines would look like? Can you fill-in the blanks?

Code:
latitude = _____; // convert the string hazardsLatitude to a double here
longitude = _____; // convert the string hazardsLongitude to a double here

I'm feeling so silly right now :eek:

if i'm to go by what i've read above it's
Code:
NSString *aString = [NSString stringWithFormat: @"%f", doubleValue];

PLEASE be right :D
 
Last edited by a moderator:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.