Geocoder throwing odd exception - ios

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"];

Related

Nearest location from current location in map in 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.

convert NSArray to MKPlacemark

I have a forward geocode block. like this:
[_geoCoder geocodeAddressString:searchString completionHandler:^(NSArray *placemarks, NSError *error) {....}];
As is, the geocode data stores in the NSArray * placemarks. Now I would like to do some annotation to the map, The addAnnotation method requires a MKPlacemark, so how do I convert the place mark in NSArrayinto a MKPlacemark? Thanks.
Here's what you want to do: Iterate through the parameters array - meaning, fetch each item from the array. As we're fetching the items, we want to create MKPlacemark objects using the data the items contain.
The Objective-C language gives us a special tool that allows us to iterate through the array - the "forin" loop:
for (CLPlacemark *placemark in placemarks)
{
// insert code here
}
Now, we want to create an MKPlacemark object from "placemark": (Note: An MKPlacemark object is a CLPlacemark object)
MKPlacemark *mkPlacemark = [MKPlacemark initWithCoordinate:(CLLocationCoordinate2D)coordinate
addressDictionary:(NSDictionary<NSString *,id> *)addressDictionary;]

Convert a place String to a CLLocation

I'm having a bug with the convertion of an NSString (which contains a place from a UITextField input) to a CLLocation.
Here is the method supposed to process the convertion:
- (void)geoCodeForAddress:(NSString *)address {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:address completionHandler:^(NSArray* placemarks, NSError* error){
dispatch_async(dispatch_get_main_queue(), ^{
CLPlacemark *placeMark = [placemarks lastObject];
if (placeMark.location != nil) {
self.actionLocation = placeMark.location;
} else {
self.actionLocation = nil;
}
if(self.event)
[self.tableView reloadData];
});
}];
}
My problem is, this method returns the wrong location for some specific strings. For instance, whenever I try to use "la patache paris" as an input, it returns a location in the wrong city though when I try the same exact string in Maps, it's finding the right place.
The method geocodeAddressString:completionHandler: is a CoreLocation method from the CLGeocoder class so there is no way I can see what's going on in it.
Would someone have some lead to find out why this is behaving weirdly ?
Thank you.

Checking Proximity of two Locations in IOS

I have an array of locations and when I add another I want to be able to check if the other locations in the array are within a block of the new one. This is the Code I have to find the current location:
//Geocoding Block
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
The array has yet to be created because I want to figure this out first, I dont know what should be held in the array (string...). I know how to do a search I just need to know how to compare the locations.
You can get the distance between two locations using the distanceFromLocation: method on CLLocation. (You can get a CLLocation out of a CLPlacemark with myPlacemark.location.) So if you have an array of CLLocation objects, and you want to find the ones that are within one block (1/20 mile, or about 80 meters), you can do this:
NSMutableArray *locationsWithinOneBlock = [NSMutableArray new];
for (CLLocation *location in myLocations) {
if ([location distanceFromLocation:targetLocation] <= 80.0)
[locationsWithinOneBlock addObject:location];
}
This assumes you have an array myLocations of CLLocation objects that you want to filter against a single CLLocation called targetLocation.

Deallocation error in Xcode while using ARC

Im setting up a map, with some MKAnnotation. When i add them to the map, I receive this message:
An instance 0xbe62850 of class ENTAnottation was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
(
Context: 0x0, Property: 0xbe66b30>
If i am not mistaken, that means that an object has been deallocated while their observer are still alive. How can I know wich are the observers? and, even if I find them... isn't explicit deallocation forbidden with ARC? if thats true, i could not deallocate them... so... what could i do?
Thank you.
-------EDIT------
By request, I post my code. I make a call to a web that returns me a JSON with the values that I need to set my Annotations:
- (void)requestFinished:(ASIHTTPRequest *)request
{
responseString = [request responseString];
id jsonObject = [responseString objectFromJSONString];
NSLog(#"From the JSON: %#", responseString);
NSMutableArray *lat = [jsonObject valueForKeyPath:#"latitud"];
NSMutableArray *lon = [jsonObject valueForKeyPath:#"longitud"];
NSMutableArray *azafatas = [jsonObject valueForKeyPath:#"azafata"];
NSMutableArray *usernames = [jsonObject valueForKeyPath:#"username"];
NSMutableArray *mapazafatas=[[NSMutableArray alloc]init];
for(int i=0;i<[lat count]; i++)
{
ENTAnottation *azafata=[[ENTAnottation alloc]init];
double latidouble=[[lat objectAtIndex:i]doubleValue];
double longdouble=[[lon objectAtIndex:i]doubleValue];
CLLocationDegrees lati=latidouble;
CLLocationDegrees longi=longdouble;
CLLocationCoordinate2D coords=CLLocationCoordinate2DMake(lati, longi);
NSString *nombre=[azafatas objectAtIndex:i];
NSString *email=[usernames objectAtIndex:i];
azafata.coordinate=coords;
azafata.title=nombre;
azafata.username=email;
[mapazafatas addObject:azafata];
//[mapa addAnnotation:azafata];
}
for (int i=0;i<[mapazafatas count];i++)
{
[mapa addAnnotation:[mapazafatas objectAtIndex:i]];
}
}
After that, the app crashes, despite it goes through my code without any problem.
Solved. Obviously, if you pass an impossible pair of coordinates it throws to your face that very clear, and impossible to confuse anybody, error message. Pity me...

Resources