Convert to NSArray - iOS sdk - iphone

Is there a place where I can read up on this or maybe better to give me an example, how to change this code into an NSArray?
-(void)loadOurAnnotations
{
CLLocationCoordinate2D workingCoordinate;
workingCoordinate.latitude = -37.711455; //This has to be an integer
workingCoordinate.longitude = 176.285013; //This has to be an integer
MyAnnotation *myLocation1 = [[MyAnnotation alloc] initWithCoordinate:workingCoordinate]; //The pointer has to be set to an array
[myLocation1 setTitle:#"The Palms Cafe"]; //The pointer and the setTitle here
[myLocation1 setSubtitle:#"157 Domain Road - (07) 542 2430"]; //The pointer and the setSubTitle here
[myLocation1 setAnnotationType:MyAnnotationTypeMine]; //again the pointer here
[mapView addAnnotation:myLocation1]; //and the pointer here
}
All of the pointers obviously come from the same place in the array and that whole piece of code (within the curly braces) is one record, so if I want to add another place i'll need to copy all of that again.
So what I am wanting to achieve is to set that up in a Plist, so that I can add the records in there, but only have the -(void)loadOurAnnotations be set once in the code and repeat itself. Of course if I should drop the -(void)loadOurAnnotations then that is not an issue, its just the way I have it at the moment.
As you may be able to tell by the info I gathering, these will be represented as an annotation on a MKMapView.
Any help is appreciated:-)
-Jeff

If I understood correctly,
First: you read your data from plist file into NSArray via some modal class. ( The example below "Location" just a modal class, and I fill in via core data )
// Location.h
#interface Location : NSManagedObject
#property (nonatomic, strong) NSNumber * longitude;
#property (nonatomic, strong) NSNumber * latitude;
#property (nonatomic, strong) NSString * name;
#end
// Location.h
#implementation Location
#dynamic longitude;
#dynamic latitude;
#dynamic name;
#end
Second: in your "loadOurAnnotations" method, iterate all values in "locationArray" which contains Location objects and for each Location object, I create PinLocation instance ( subclass of MkAnnotation ), and add them into mapView.
for(Location *location in locationArray) {
NSString *name = [location name];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[location latitude] doubleValue];
coordinate.longitude = [[location longitude] doubleValue];
PinLocation *pinLocation = [[PinLocation alloc] initWithName:name coordinate:coordinate];
[self.mapView addAnnotation:pinLocation];
}

Related

Compare Position to Coordinates in NSMutableArray

I have an NSMutableArray that stores IDs, latitudes, longitudes, etc... I have a requirement to compare the user's current location to the latitudes and longitudes of the items stored in the array below.
I know how to get the user's current coordinates, but I don't know how to access the coordinates in the array or how to compare the distances.
The array is an NSMutableArray called scrolledPast (see below). Lets say the current user's coordinates are 21.31,-157.86. How would I even start? Any guidance would be greatly appreciated. Thank you al for your wonderful help!
array: (
{
key1 = 80;
key2 = "11:34 PM";
key3 = "place1";
key4 = "21.3111656";
key5 = "-157.8606953";
},
{
key1 = 251;
key2 = "11:34 PM";
key3 = "place2";
key4 = "21.310672";
key5 = "-157.8611839";
},
{
key1 = 79;
key2 = "11:34 PM";
key3 = "place3";
key4 = "21.3106798";
key5 = "-157.8612934";
}
)
Here is the code that generates the above array:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:placeId forKey:#"key1"];
[dict setObject:currentTime forKey:#"key2"];
[dict setObject:textForMyLabel forKey:#"key3"];
[dict setObject:placeLatitude forKey:#"key4"];
[dict setObject:placeLongitude forKey:#"key5"];
[scrolledPast addObject:dict];
NSLog(#"array: %#", scrolledPast);
You have an array of dictionaries. You can access elements in the following way:
for (NSDictionary *dict in scrolledPast) {
NSString *lat = dict[#"key4"];
NSString *lng = dict[#"key5"];
// compare distance here
}
For comparing distances it's best to use CLLocation's distanceFromLocation: (I suppose that internally it uses the Haversine formula).
I will take another approach to solve your problem. I will create a new object called Coordinate for example to save the data like:
#import "Coordinates.h"
#interface Coordinates ()
#property (nonatomic, strong) NSNumber *identifier;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSDate *date;
#property (nonatomic, assign) CGPoint coordinate;
#end
#implementation Coordinates
- (id) initWithDictionary: (NSDictionary *) dict
{
//Create and hydrate object
}
- (float) comparePointWithPoint: (CGPoint) point
{
CGFloat xDist = (self.coordinate.x - point.x);
CGFloat yDist = (self.coordinate.y - point.y);
CGFloat distance = sqrt((xDist * xDist) + (yDist * yDist));
return distance;
}
You can use CLLocation class instead of CGPoint if you want to save the coordinates.
First create a model object for each store and implement useful methods within the class:
Store.h:
#interface Store : NSObject
#property (strong, nonatomic) NSString *storeId; // Don't use "id" as that is type in Objective-C
#property (assign, nonatomic) NSUInteger timeHour;
#property (assign, nonatomic) NSUInteger timeMinute;
#property (strong, nonatomic) NSString *label;
#property (assign, nonatomic) float lat;
#property (assign, nonatomic) float lng; // not "long" as that is a type
- (id)initWithDictionary:(NSDictionary *)dict;
- (BOOL)isStoreNearLatitude:(float)lat longitude:(float)lng;
#end;
Store.m:
#import "Store.h"
#implementation Store
#synthesize storeId, timeHour, timeMinute, label, lat, lng;
- (id)initWithDictionary:(NSDictionary *)dict {
self = [super init];
if (self) {
self.storeId = [dict objectForKey:#"key1"];
// etc.
}
return self;
}
- (BOOL)isStoreNearLatitude:(float)lat longitude:(float)lng {
// You will never get an exact match, so you will need to match the lat/long within
// a certain tolerance. You might want to pass it in so it can change at runtime...
#define TOLERANCE 10.0f
return
fabs(self.lat - lat) < TOLERANCE &&
fabs(self.lng - lng) < TOLERANCE;
}
#end
You will find that this new Store object becomes more and more useful as your project progresses.

Objective- C prevent NSString from being released/ dealloc

Total newbie Iphone/ Obj. C question:
I have a class called Location, in the Location.h i declare:
#interface Location : NSObject
{
NSString *lat;
NSString *lon;
}
In my Location.m i have to methods:
-(void)setLatLon:(NSString*)lati:(NSString*)longi
{
NSLog(#"called setLatLon");
lat = lati;
lon = longi;
}
which I call on location updates from the LocationManager. Now when I try to send that out as a JSON with
-(void)sendLocation
{
NSDictionary *sendData = [NSDictionary dictionaryWithObjectsAndKeys:
imei, #"imei",
lat, #"lat",
lon, #"lon",
nil];
...}
i get this error:
*** -[CFString retain]: message sent to deallocated instance 0xc05b5d0
So lat & lon seem to be deallocated. How can I prevent that or have I implemented a totally stupid 'design' here?
You should declare retain/strong properties for the iVars you're trying to use. I'm not sure how you're storing the "imei", but the lat and lon are being deallocated because you're not retaining then. Try something like:
#interface Location : NSObject
{
NSString *lat;
NSString *lon;
}
#property (retain) NSString *lat;
#property (retain) NSString *lon;
and on the .m file:
#synthesize lat, lon;
-(void)setLatLon:(NSString*)lati:(NSString*)longi
{
NSLog(#"called setLatLon");
self.lat = lati;
self.lon = longi;
}
and
-(void)sendLocation
{
NSDictionary *sendData = [NSDictionary dictionaryWithObjectsAndKeys:
imei, #"imei", //dunno what is this
self.lat, #"lat",
self.lon, #"lon",
nil];
...}
You could add properties as other responses have suggested and as you start moving forward to work on more advanced projects I definitely agree with that approach, especially if you want to take advantage of ARC and other time-saving and error-avoiding features of Objective-C.
Aside from that, however, you can fix your code as it is currently written with a minimal change. Change this:
lat = lati;
lon = longi;
to this:
lat = [lati retain];
lon = [longi retain];
This will cause your code to retain the references it has to these variables. IF you do this approach, you will want to make sure to release your variables when you are done, usually in a dealloc method. If you don't take care of that, you will be creating memory leaks.
Try this:
#interface Location : NSObject {
NSString *lat;
NSString *lon;
}
#property (nonatomic, strong) NSString *lon;
#property (nonatomic, strong) NSString *lat;
#implementation Location
#synthesize lon;
#synthesize lat;
-(void)setLatLon:(NSString*)lati:(NSString*)longi
{
self.lat = lati;
self.lon = longi;
}
And If you want dive deeply in ios dev, you should read follow article:
Advanced Memory Management Programming Guide and The Objective-C Programming Language

iPhone: MKMapView and multi-pin

I want to show multiple pin in MKMapView for "Sports" category places in my program. Could someone guide me how can i show multi pin in MKMapView for "Sports" places around 20 miles distance from the current location?
thanks.
Create annotation objects and add them to the map. I called them LocalAnnotation.
LocalAnnotation.h:
#interface LocationAnnotation : NSObject <MKAnnotation>
{
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
-initWithCoordinate:(CLLocationCoordinate2D)inCoord;
#end
LocalAnnotation.m:
#import "locationAnnotation.h"
#implementation LocationAnnotation
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
-init
{
return self;
}
-initWithCoordinate:(CLLocationCoordinate2D)inCoord
{
coordinate = inCoord;
return self;
}
#end
Within the method using the map:
//erase all annotations
[self.geoMap removeAnnotations:[self.geoMap annotations]]; //geoMap is an MKMapView object.
//Set the pin
CLLocationCoordinate2D newCoordinate;
newCoordinate.latitude = (CLLocationDegrees) [exifGeoLatitudeNumeric doubleValue]; //exifGeoLatitudeNumeric is a NSNumber representing a coordinate in the format +/-23.5435423
newCoordinate.longitude = (CLLocationDegrees) [exifGeoLongitudeNumeric doubleValue]; //exifGeoLongitudeNumeric is a NSNumber representing a coordinate in the format +/y23.5435423
LocationAnnotation *newAnnotation = [[LocationAnnotation alloc] initWithCoordinate:newCoordinate];
[self.geoMap addAnnotation:newAnnotation];

Converting HTML to Plain Text for MapKit Annotations

I have a problem when I use an annotation to see information with MapKit.
I ran into a similar issue. You're not crazy. I believe it's a bug in the MapKit code. The Annotation object doesn't create it's own copy of the strings you pass to it. When your string goes out of scope, the map makes a bad reference. Try re-allocating the strings before you pass them. Like so:
NSString *tempT = [[NSString alloc] initWithString:itemT];
NSString *tempA = [[NSString alloc] initWithString:itemA];
addAnnotation = [[MapAnnotation alloc] initWithCoordinate:essai :tempT :tempA];
And then don't release them until you're finished displaying the map.
I ran into the exact same problem, as Jonesy mentioned, but there is a fix. I'm not sure what kind of class you have for your annotations, but I use this:
Annotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#interface LocationAnnotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString* title;
NSString* subtitle;
}
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* subtitle;
- (id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString*) t
subtitle:(NSString*) st;
- (void)moveAnnotation:(CLLocationCoordinate2D) newCoordinate;
- (NSString*)subtitle;
- (NSString*)title;
#end
And Annotation.m:
#import "LocationAnnotation.h"
#implementation LocationAnnotation
#synthesize coordinate, pinColor, title, subtitle;
- (NSString *)subtitle {
return subtitle;
}
- (NSString *)title {
return title;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D) c
title:(NSString*)t
subtitle:(NSString*)st
{
coordinate = c;
self.title = t;
self.subtitle = st;
return self;
}
- (void)moveAnnotation:(CLLocationCoordinate2D)newCoordinate
{
coordinate = newCoordinate;
}
- (void)dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end
To implement it:
Annotation* ann = [[[Annotation alloc] initWithCoordinate:startLocation title:someStringAutoreleasedOrNot subtitle:someOtherStringAutoreleasedOrNot] autorelease];
[yourMapView addAnnotation:ann];
Really, the key here is that in the annotation class, the title and subtitle properties are declared as type copy. This makes a new copy of the string you assign it, so it can be released without causing the crash that you are having.
I dont see stringByStandardizingWhitespace method call in the above code you pasted... It would be helpful if you can post the code which has the error. Use debugger to know where the error is occuring...
Also one error which is not related to the syntax/error you specified but would effect the logic later:
you are assigning the gps_long tag tpo lat and vice versa ...

iPhone Objective C - error: pointer value used where a floating point value was expected

I do not understand why i am getting this error. Here is the related code:
Photo.h
#import <CoreData/CoreData.h>
#class Person;
#interface Photo : NSManagedObject
{
}
#property (nonatomic, retain) NSData * imageData;
#property (nonatomic, retain) NSNumber * Latitude;
#property (nonatomic, retain) NSString * ImageName;
#property (nonatomic, retain) NSString * ImagePath;
#property (nonatomic, retain) NSNumber * Longitude;
#property (nonatomic, retain) Person * PhotoToPerson;
#end
Photo.m
#import "Photo.h"
#import "Person.h"
#implementation Photo
#dynamic imageData;
#dynamic Latitude;
#dynamic ImageName;
#dynamic ImagePath;
#dynamic Longitude;
#dynamic PhotoToPerson;
#end
This is a mapViewController.m class i have created. If i run this, the CLLocationDegrees CLLat and CLLong lines:
CLLocationDegrees CLLat = (CLLocationDegrees)photo.Latitude;
CLLocationDegrees CLLong = (CLLocationDegrees)photo.Longitude;
give me the error : pointer value used where a floating point value was expected.
for(int i = 0; i < iPerson; i++)
{
//get the person that corresponds to the row indexPath that is currently being rendered and set the text
Person * person = (Person *)[myArrayPerson objectAtIndex:i];
//get the photos associated with the person
NSArray * PhotoArray = [person.PersonToPhoto allObjects];
int iPhoto = [PhotoArray count];
for(int j = 0; j < iPhoto; j++)
{
//get the first photo (all people will have atleast 1 photo, else they will not exist). Set the image
Photo * photo = (Photo *)[PhotoArray objectAtIndex:j];
if(photo.Latitude != nil && photo.Longitude != nil)
{
MyAnnotation *ann = [[MyAnnotation alloc] init];
ann.title = photo.ImageName;
ann.subtitle = photo.ImageName;
CLLocationCoordinate2D cord;
CLLocationDegrees CLLat = (CLLocationDegrees)photo.Latitude;
CLLocationDegrees CLLong = (CLLocationDegrees)photo.Longitude;
cord.latitude = CLLat;
cord.longitude = CLLong;
ann.coordinate = cord;
[mkMapView addAnnotation:ann];
}
}
}
NSNumber is not a float type, but a pointer, so you need to do this to convert it:
CLLocationDegrees CLLat = (CLLocationDegrees)[photo.Latitude doubleValue];
CLLocationDegrees CLLong = (CLLocationDegrees)[photo.Longitude doubleValue];