Nearest location from current location in map in IOS - ios

Have a button on a mapview which is used to calculate the nearest location from the locations i have plotted on map. I have applied some code but when i click the button the app crashes by giving this error,
[__NSDictionaryI coordinate]: unrecognized selector sent to instance 0x174e61b40
2017-10-31 15:20:00.434548 GuardsAutoZone[735:114166] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI coordinate]: unrecognized selector sent to instance 0x174e61b40'
* First throw call stack:
(0x1937d11b8 0x19220855c 0x1937d8268 0x1937d5270 0x1936ce80c 0x10011cec8 0x1996bbd30 0x1996bbcb0 0x1996a6128 0x1996bb59c 0x1996bb0c4 0x1996b6328 0x199686da0 0x199e7075c 0x199e6a130 0x19377eb5c 0x19377e4a4 0x19377c0a4 0x1936aa2b8 0x19515e198 0x1996f17fc 0x1996ec534 0x1000fc994 0x19268d5b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
My code is this, i'm in doubt that my code is right for finding nearest location or not? The code i used is,
- (IBAction)nearLocation:(id)sender {
CLLocation *userLocation = self.mapView.userLocation.location;
NSMutableDictionary *distances = [NSMutableDictionary dictionary];
for (MapPin *obj in locations) {
CLLocation *loc = [[CLLocation alloc] initWithLatitude:obj.coordinate.latitude longitude:obj.coordinate.longitude];
CLLocationDistance distance = [loc distanceFromLocation:userLocation];
NSLog(#"Distance from Annotations - %f", distance);
[distances setObject:obj forKey:#( distance )];
}
NSArray *sortedKeys = [distances allKeys];
NSLog(#"List %#",sortedKeys);
//NSArray *closestKeys = [sortedKeys subarrayWithRange:NSMakeRange(0, MIN(3, sortedKeys.count))];
// NSArray *closestAnnotations = [distances objectsForKeys:closestKeys notFoundMarker:[NSNull null]];
}
the error screen shot is ,
enter image description here

Use this set of code to get the distance between two latitude and longitude.
In Objective C
#class CLLocation
CLLocation *location1 =[[CLLocation alloc] initWithLatitude:[#"23.039698" doubleValue] longitude:[#"77.571663" doubleValue]];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:[#"23.0422" doubleValue] longitude:[#"72.5644" doubleValue]];
CLLocationDistance distanceMeter = [location distanceFromLocation:location2];
And in Swift
import CoreLocation
let location1 = CLLocation(latitude: 5.0, longitude: 5.0)
let location2 = CLLocation(latitude: 5.0, longitude: 3.0)
let distanceInMeters = location1.distance(from: location2)
The above code will give you the distance in meters.
Once you will get the distance between the two annotation through the coordinate then you can implement the same as per your requirement.

It seems locations is an array of NSDictionary. In the for loop you cast the elements to MapPin* but that just makes the compiler happy. Accessing obj.coordinate.latitude will call selector coordinate on object obj. And the exception tells us its an NSDictionary object.
Check what kind of object locations really is at runtime and change your code accordingly.

Related

How to get the distance of multiple location in array from one location and Sort that array by nearest distance in iOS?

I am working on a project in which I have to show the distance of multiple locations from one location. locations are based on latitude and longitude.
I am using the following code to get the distance between two locations is shows nearly same distance
CLLocation *locationA = [[CLLocation alloc] initWithLatitude:28.6379 longitude: 77.2432];CLLocation *locationB = [[CLLocation alloc] initWithLatitude:28.6562 longitude:77.2410];CLLocationDistance distance = [locationA distanceFromLocation:locationB];NSLog(#"Distance is %f",distance);float i = distance/1000;NSLog(#"distance between two places is %f KM", i);
but now i am struct to get the distance of multiple locations from my location: locationA.
for example I take NSArray for latitude and longitude as
NSArray * latitudeArray = [[NSArray alloc]initWithObjects:#"28.6129",#"28.6020",#"28.5244", nil];NSArray * longitudeArray = [[NSArray alloc]initWithObjects:#"77.2295",#"77.2478",#"77.1855", nil];
Please help me to resolve it..
Take locationA as one location..
Please help me to sort the Array by nearest Distance..
First of all, don't create two array for latitude and longitude, It should be one array of CLLocations.
NSMutableArray locationsArray = [[NSMutableArray alloc] init];
//This is just for example, You should add locations to this array according to format of data you have available.
[locationsArray addObject:[[CLLocation alloc] initWithLatitude:28.6379 longitude:77.2432]];
[locationsArray addObject:[[CLLocation alloc] initWithLatitude:28.6020 longitude:77.2478]];
[locationsArray addObject:[[CLLocation alloc] initWithLatitude:28.5244 longitude:77.1855]];
Now, Take some reference location,
CLLocation *yourLocationA ; //set whatever value you have..
You can sort array of location with following.
[locationsArray sortUsingComparator:^NSComparisonResult(CLLocation *obj1Location,CLLocation *obj2Location) {
CLLocationDistance obj1Distance = [obj1Location distanceFromLocation: yourLocationA];
CLLocationDistance obj2Distance = [obj2Location distanceFromLocation: yourLocationA];
return (obj1Distance > obj2Distance);
}];

create CLLocation object in objective-c

I can initialize a CLLocation object by providing latitude and longitude like below:
CLLocation *location = [[CLLocation alloc] initWithLatitude:-43.242534 longitude:-54.93662];
How can I initialize a CLLocation object with not only latitude and longitude but also accuracy values?
As per apple docs you can use the following function:
double desired_horizontal_accuracy = 200.0 // in meters
double desired_vertical_accuracy = 200.0 // in meters
[[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(-43.242534,-54.93662)
altitude:-1
horizontalAccuracy:desired_horizontal_accuracy
verticalAccuracy:desired_vertical_accuracy
timestamp:[NSDate date]]
In the example, for the parameters altitude and timestamp, I put the same defaults as what the apple docs say are used on -initWithLatitude:longitude:

Sending CLLocationCoordinate2D to parameter of incompatible type my code in Xcode 4.5

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
}

Geocoder throwing odd exception

I have a method that is triggered on the press of a button. This is most of the implmentation:
[self.placeDictionary setValue:#"166 Bovet Rd" forKey:#"Street"];
[self.placeDictionary setValue:#"San Mateo" forKey:#"City"];
[self.placeDictionary setValue:#"CA" forKey:#"State"];
[self.placeDictionary setValue:#"94402" forKey:#"ZIP"];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:self.placeDictionary completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
PFGeoPoint* userLocation = [PFGeoPoint geoPointWithLatitude:coordinate.latitude longitude:coordinate.longitude];
NSLog(#"%f,%f", userLocation.latitude, userLocation.longitude);
} else {
NSLog(#"location error");
return;
}
}];
However, I am getting the following exception:
*** WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSUnknownKeyException> [<__NSDictionaryI 0x873a3c0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key Street.
I have absolutely no idea what this exception means. Could someone help me understand why it is producing this?
First off, you are trying to add objects to an immutable dictionary. The part of the exception beginning [<__NSDictionaryI 0x873a3c0> setValue:forUndefinedKey: gives a class name of __NSDictionaryI, which is an immutable member of the NSDictionary class cluster - so you cannot add any objects to it at run-time. You need to ensure that self.placeDictionary is assigned to an NSMutableDictionary instance before this code is called.
Unfortunately, you are also using the wrong method to add the objects - you're using setValue:forKey: instead of setObject:forKey:. Since this method is part of the NSKeyValueCoding informal protocol, you're not stopped from doing this at compile time. You should instead use setObject:forKey: which is the correct method to set key-value pairs on an NSMutableDictionary. After you correct the first issue, replace the setValue:forKey: calls with setObject:forKey:, for example:
[self.placeDictionary setObject:#"San Mateo" forKey:#"City"];

How do I access a custom object in memory from a view controller?

In my app I fetch a coredatabase and put results into an array called self.stores. I convert those store locations to MyLocation objects which have a distance property. I plot the MyLocation objects like so:
- (void)plotStorePositions:(NSString *)responseString {
for (id<MKAnnotation> annotation in _mapView.annotations) {
[_mapView removeAnnotation:annotation];
}
//CYCLE THRU STORE OBJECTS
for (Store * storeObject in self.stores) {
NSString * latitude = storeObject.latitude;
NSString * longitude = storeObject.longitude;
NSString * storeDescription = storeObject.name;
NSString * address = storeObject.address;
//CREATE MYLOCATION OBJECTS
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;
MyLocation *annotation = [[MyLocation alloc] initWithName:storeDescription address:address coordinate:coordinate distance:0];
//CREATE A PIN FOR EACH MYLOCATION ANNOTATION
CLLocation *pinLocation = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
//SET USERLOCATION (Must move this code out)
self.userLocation = [[CLLocation alloc] initWithLatitude:self._mapView.userLocation.coordinate.latitude longitude:self._mapView.userLocation.coordinate.longitude];
//SET USERLOCATION TO APPDELEGATE (Must move this code out)
AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];
myDelegate.userLocation = self.userLocation;
//CALCULATE DISTANCE AND SET ITS THAT MYLOCATION's DISTANCE PROPERTY
CLLocationDistance calculatedDistance = [pinLocation distanceFromLocation:userLocation];
annotation.distance = calculatedDistance/1000;
[_mapView addAnnotation:annotation];
}
}
This is in a mapview. I then have a tableview where I fetch the same coredatabase and get self.stores again. Then I cycle through that array of self.stores to create STORE storeObjects to put into my tableview cells. But I want to sort those cells. How do I get MyLocation objects which should be in memory? Do I need to pass them to the appDelegate or to the tableview controller?
As you are using Core Data, your best option is to use a NSFetchedResultsController to populate your table view.
All you need then is the managed object context, either from another controller or the app delegate.

Resources