i have a Problem with the Annotiations, the Code is ok, but i read with the Variable [i] more than one Username and Location. On the Map i have only the last reading Username and Location Pin.
In the Debug Box , he show me all Names and Location, but i have only 1 Pin on the Map.
Here is the Code.
for (int i=1; i<4; ++i) {
[User whereKey:#"index" equalTo:#(i)];
PFObject *test1 = [User getFirstObject];
ann.title = [test1 objectForKey:#"username"] ;
PFGeoPoint *geopoint = [test1 objectForKey:#"currentLocation"];
CLLocationCoordinate2D coord = { geopoint.latitude, geopoint.longitude };
ann.coordinate = coord;
[MapView addAnnotation:ann];
}
Thanks for your Help ;)
The ann object which you are adding to the map needs to be created separately for each annotation that you add.
In the code shown, the ann object is not being created inside the for loop for each annotation so you end up with only one annotation object with the coordinates of the last item.
Create the ann object (alloc+init) inside the loop before setting the properties on it.
Related
I have a map app that allows the User to save annotations as a favorite to a mutable array. All favorite annotations can then be displayed when the User chooses to.
Annotations added to the mutable array are of the MKPointAnnotation class. I can correctly add annotations to the mutable array, but I haven't come up with a working solution that correctly removes a specific annotation from the mutable array. How can a specific annotation be removed from the mutable array that contains multiple annotations that were saved as favorites? Several non-working solutions are found in my sample code.
//** Correctly adds a favorite annotation to the mutable array favoriteAnnotationsArray **
-(void)addToFavoriteAnnotationsArray{
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
NSArray *components = [favoritesString componentsSeparatedByString:#","];
annotation.coordinate = CLLocationCoordinate2DMake([components[1] doubleValue], [components[0] doubleValue]);
annotation.title = [components[2] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
[self.favoriteAnnotationsArray addObject:annotation];
}
//** Need to remove a favorite annotation from the mutable array favoriteAnnotationsArray **
-(void)removeObjectFromFavoriteAnnotationsArray{
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
NSArray *components = [favoritesString componentsSeparatedByString:#","];
annotation.coordinate = CLLocationCoordinate2DMake([components[1] doubleValue], [components[0] doubleValue]);
annotation.title = [components[2] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
//** Used in first non-working solution below **
//NSMutableArray *objectToRemoveArray = [[NSMutableArray alloc] init];
//[objectToRemoveArray addObject:annotation];
//** The following three lines didn't remove any annotations from array **
//[self.favoriteAnnotationsArray removeObjectsInArray:objectToRemoveArray];
//[self.favoriteAnnotationsArray removeObject:annotation];
//[self.favoriteAnnotationsArray removeObjectIdenticalTo:annotation];
//** This only removes the last object in array and not necessarily the correct annotation to remove **
[self.favoriteAnnotationsArray removeLastObject];
}
You will need to specify an unique annotation from the favoriteAnnotationsArray in order for it o be removed successfully.
Maybe you can try something as follows:
-(void)removeAnnotationFromFavoriteAnnotationsArrayWithTitle: (NSString *) titleString {
for(int i=0; i<self.favoriteAnnotationsArray.count; i++) {
MKPointAnnotation *annotation = (MKPointAnnotation *)[self.favoriteAnnotationsArray objectAtIndex:i];
NSString * annotationTitle = annotation.title;
if([annotationTitle isEqualToString:titleString]) {
[self.favoriteAnnotationsArray removeObject:annotation];
break;
}
}
}
If title is not unique enough for you to differentiate between annotations, then you might consider subclassing MKAnnotation and add an unique property and pass it to the above function instead of the title.
One approach is to iterate through your annotation array and find the one to remove. For example:
- (void)addToFavoriteAnnotationsArray:(NSString *)string {
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
NSArray *components = [string componentsSeparatedByString:#","];
annotation.coordinate = CLLocationCoordinate2DMake([components[1] doubleValue], [components[0] doubleValue]);
annotation.title = [components[2] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
[self.favoriteAnnotationsArray addObject:annotation];
}
- (void)removeObjectFromFavoriteAnnotationsArray:(NSString *)string {
NSArray *components = [string componentsSeparatedByString:#","];
NSString *titleOfAnnotationToRemove = [components[2] stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
CLLocationCoordinate2D coordinateOfAnnotationToRemove = CLLocationCoordinate2DMake([components[1] doubleValue], [components[0] doubleValue]);
for (NSInteger i = 0; i < self.favoriteAnnotationsArray.count; i++) {
id<MKAnnotation>annotation = self.favoriteAnnotationsArray[i];
if ([annotation.title isEqualToString:titleOfAnnotationToRemove] && coordinateOfAnnotationToRemove.latitude == annotation.coordinate.latitude && coordinateOfAnnotationToRemove.longitude == annotation.coordinate.longitude) {
[self.favoriteAnnotationsArray removeObjectAtIndex:i];
break;
}
}
}
Or if you wanted to match on title, alone, then remove the coordinates from the if statement above. Also note that I've added the string as a parameter to these methods. It's always better to pass a parameter to a method rather than relying upon some property.
Frankly, though, when the user is selecting one to remove, you probably don't want them to have to manually enter the name and coordinates again. You probably want them to pick one from the list. So you might show them a table view of the annotations and when they say they want to remove the third one, you'd do just pass the index to a method like this:
- (void)removeObjectFromFavoriteAnnotationsArray:(NSInteger)index {
[self.favoriteAnnotationsArray removeObjectAtIndex:index];
}
By the way, all of the above routines remove the annotation from your array. If you've also added this annotation to the map view, remember to remove it from there, too.
I am creating an iOS application where I have some data structure containing multiple coordinates and I know the current user location. I want to fill the cells of the TableView with the distance from the user's current location to the locations in the TableView.
I was wondering when I should calculate the distance between the user's current location and all the locations in the TableView. Should I calculate all these distances when the application starts? What should I do when the user changes location? Set some sort of timer to check if the user's position changed and recalculate the distances every time the user's position changed?
I should also note, I am giving them the ability to sort this TableView by distance.
Thanks in advance.
You can user CLLocationManagerDelegate's locationManager:didUpdateLocations: Method.
This method is called when user's location will update so you can call your method to show data in tableview from user's current location.
below is some code for sorting your arryOfLocation.
for (int i = 0; i < arrySortByLocation.count; i++)
{
//Current Location Details
NSMutableDictionary *dict = [[arrySortByLocation objectAtIndex:i] mutableCopy];
CLLocationDegrees latitude = [dict[#"city_lat"] doubleValue];
CLLocationDegrees longitude = [dict[#"city_lng"] doubleValue];
CLLocation *location = [[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
CLLocationDistance distance = [appDele.userLocation distanceFromLocation:location];
dict[#"distance"] = [#(distance) stringValue];
//Storing as string since latitude and longitude is also string values
//Since its a dictionary storing as NSNumber is better
[arrySearchLocation setObject:dict atIndexedSubscript:i];
}
//sorting based on distance
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"distance.doubleValue" ascending:YES];
[arrySortByLocation sortUsingDescriptors:#[descriptor]];
}
Hope this will help you..
I am new to Xcode. I am developing a vehicle tracking app for that I need to display more annotation points simultaneously. For this I need to store the coordinates in the array but it shows the error: Sending CLLocationCoordinate2D to parameter of incompatible type
my code is:
NSString *urlMapString=[NSString stringWithFormat:#"http://logix.com/logix_webservice/mapvehiclelist.php?uid=20&format=json"];
NSURL *urlMap=[NSURL URLWithString:urlMapString];
NSData *dataMap=[NSData dataWithContentsOfURL:urlMap];
if(dataMap!=NULL){
NSError *errorMap;
NSMutableArray *coordinates = [[NSMutableArray alloc]init];
NSDictionary *jsonMap = [NSJSONSerialization JSONObjectWithData:dataMap options:kNilOptions error:&errorMap];
NSArray *resultsMap = [jsonMap valueForKey:#"posts"];
for(int count=1;count<resultsMap.count;count++)
{
NSDictionary *resMap = [[resultsMap objectAtIndex:count]valueForKey:#"post"];
NSString *latOrgstring =[resMap valueForKey:#"latitude"];
latitude=[latOrgstring doubleValue];
NSString *longitudeString=[resMap valueForKey:#"longitude"];
longitude=[longitudeString doubleValue];
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
[coordinates addObject:center]; //here it shows the error
}
}
Kindly advice me to solve this problem.
Thank you...
CLLocationCoordinate2D center isn't an object. You can store only objects in NSArray.
Use CLLocation for this.
CLLocation *location = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
As already mentioned, you can only add objects to an NSArray.
CLLocationCoordinate2D is not an object -- it is a C struct.
The code you posted itself has one solution:
Create a NSDictionary with the latitude and longitude as key/value pairs and add the resulting dictionary object to the array.
Another approach is to create a CLLocation as shown in another answer.
A third idea is what #trojanfoe answered previously which is to wrap the struct in an NSValue.
However, note that there is a convenient NSValue addition specifically for MapKit that adds these two useful helper methods:
valueWithMKCoordinate: which returns an NSValue given a CLLocationCoordinate2D
MKCoordinateValue which returns a CLLocationCoordinate2D for the NSValue
For an example, see How to store CLLocationCoordinate2D?.
A final (at least in this answer) alternate approach which I would highly recommend instead of all the above is this...
Why do you want to store only the coordinates in an array?
Wouldn't you want to know what the coordinates are for (which vehicle, place, etc)?
Why not create a custom class that implements, say, the MKAnnotation protocol and has not only the coordinates (as a CLLocationCoordinate2D property) but also all the other information related to the coordinate? The class would be a subclass of NSObject<MKAnnotation>.
You could then conveniently access all the information in one place without using multiple arrays and trying to keep the objects in the same order so they all have the same index, etc.
You could then directly add these objects to an MKMapView since they implement MKAnnotation.
CLLocationCoordinate2D is a C struct, so you need to put it in NSValue container at first.
An NSValue object is a simple container for a single C or Objective-C
data item. It can hold any of the scalar types such as int, float, and
char, as well as pointers, structures, and object id references. Use
this class to work with such data types in collections (such as
NSArray and NSSet), key-value coding, and other APIs that require
Objective-C objects.
[coordinates addObject:[NSValue value:&coordinate withObjCType:#encode(CLLocationCoordinate2D)]];
Try this
CLLocationCoordinate2D new_coordinate = CLLocationCoordinate2DMake(latitude, longitude);
[points addObject:[NSValue valueWithMKCoordinate:new_coordinate]];
Or
CLLocation *location = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
[coordinates addObject: location];
Can't u directly add coordinates to mapview that means Place MKAnnotation on Mapview, instead of taking coordinates to into array ?
SEE Below i commented with lines
for(int count=1;count<resultsMap.count;count++)
{
NSDictionary *resMap = [[resultsMap objectAtIndex:count]valueForKey:#"post"];
NSString *latOrgstring =[resMap valueForKey:#"latitude"];
latitude=[latOrgstring doubleValue];
NSString *longitudeString=[resMap valueForKey:#"longitude"];
longitude=[longitudeString doubleValue];
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
-----------------------------------------
////// Annotation is MKAnnotation Subclass
Annotation * cartAnn = [Annotation new];
cartAnn.coordinate = center;
[self.mapView addAnnotation: cartAnn];
----------------------------------------------------
/////// [coordinates addObject:center]; //here it shows the error
}
Hai I am trying to display multiple annotations in mkmap. While am adding the coordinates it shows the error:"Assigning to 'CLLocationCoordinate2D' from incompatible type 'id'". I know this is a simple prob, but I have searched many times and tried a lot but none works, my code is,
for(int i=0 ; i<coordinates.count ; i++)
{
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate =[coordinates objectAtIndex:i]; //here it shows the error
point.title = #"title";
[self.mapView addAnnotation:point];
}
kindly advice me to solve this prob. Thank you...
As CLLocationCoordinate2D is not an Objective-C object, but a struct, it cannot be directly stored in an NSArray object, but rather it must be wrapped within an NSValue object.
Therefore the code to read co-ordinates from the array is probably:
CLLocationCoordinate2D coords;
[[coordinates objectAtIndex:i] getValue:&coords];
point.coordinate = coords;
However to know for sure, I would need to see how the array was created.
I have been trying to do this for a while now , but still not able to show multiple annotations.
Here is how i am storing data into NSMutableDictionary and then to NSMutableArray in AppDelegate
// set the values to mutable dictionary
[_locationDictionary setObject:latitudeObj forKey:#"latitudeValue"];
[_locationDictionary setObject:longitudeObj forKey:#"longitudeValue"];
[_locationDictionary setObject:fromUser forKey:#"fromUser"];
// add to array
[_presenceArray addObject:_locationDictionary];
And this i am doing inside another ViewController.
-(void)getPresenceData {
for(NSDictionary *dictObj in appDelegate.presenceArray) // this array that has dictionaries
{
annotation = [[Annotation alloc]init]; // Annotation Class
annotation.coordinate = CLLocationCoordinate2DMake([[dictObj valueForKey:#"latitudeValue"]doubleValue], [[dictObj valueForKey:#"longitudeValue"]doubleValue]);
annotation.title = [dictObj objectForKey:#"fromUser"];
[self.buddyDataArray addObject:annotation];
NSLog(#"buddy data array is %#", self.buddyDataArray);
[self.mapView addAnnotations:buddyDataArray];
}
You could try this way... Make sure in your presenceArray dictionaries are getting stored.
-(void)getPresenceData {
for(NSDictionary *dictObj in appDelegate.presenceArray) // this array that has dictionaries
{
annotation = [[Annotation alloc]init]; // Annotation Class
annotation.coordinate = CLLocationCoordinate2DMake([[dictObj valueForKey:#"latitudeValue"]doubleValue], [[dictObj valueForKey:#"longitudeValue"]doubleValue]);
annotation.title = [dictObj objectForKey:#"fromUser"];
[self.mapview addAnnotation:annotation];
}
}
As you are already looping than you dont need to create array of annotation objects.. You can add directly them to map as i did in above code..