I found this tutorial:
http://evilrockhopper.com/2010/01/iphone-development-reverse-geocoding/
and implemented this code:
if (reverseGeocoder != nil)
{
// release the existing reverse geocoder to stop it running
[reverseGeocoder release];
}
// use whatever lat / long values or CLLocationCoordinate2D you like here.
CLLocationCoordinate2D locationToLookup = {52.0,0};
MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:locationToLookup];
reverseGeocoder.delegate = self;
[reverseGeocoder start];
The question is, when I started reverseGeocoding, where is location string stored?
I have coordinate and I give them to reverseCeocoder to find me address, but how to get this address in some string for example?
Just read the documentation for MKReverseGeocoder:
The reverse geocoder returns information through its associated delegate object, which is an object that conforms to the MKReverseGeocoderDelegate protocol.
So you have to implement these two methods in your delegate:
– reverseGeocoder:didFindPlacemark:
– reverseGeocoder:didFailWithError:
and the geocoder will call them when it has information for you.
Related
I am trying to understand some concept here regarding delegate and callbacks. Basically I am trying to make an http-request, which is based on zipcode. So prior making http-request, I call a location-manager and grab a zipcode, however, in such duration, I have to wait async to complete that task, and get the feedback. The concern here is, the delegate I have set from location-manager, have no link with http-request class. So, I am trying to understand how can I pass the information back from delegate to http-request. I was looking into blocks, but again is there anyway in blocks that you can wait for a response of a delegate? or it can be also set as a BOOL property in async task, when completed can trigger the request. I haven't tried blocks much except for GCD, so still trying to get my heads around this.
I welcome any suggestions here.
Here is a sketch - (ignoring error conditions and location data caching issues). This could all go in the viewController. There is one block for obtaining the zip code, but the rest of it can be done through delegates if you prefer.
//initialise locationManager once (eg in viewDidLoad)
- (void) initialiseLocationManager
{
CLLocationManager* locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
[locationManager setDistanceFilter:500];
self.locationManager = locationManager;
}
//[self startLocating] whenever you want to initiate another http-request
- (void) startLocating
{
[self.locationManager startUpdatingLocation];
}
//locationManager delegate method
//this will get triggered after [self startLocating]
//when a location result is returned
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation* location = [locations lastObject];
CLGeocoder* geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error){
CLPlacemark* placemark = [placemarks objectAtIndex:0];
NSString* zip = [placemark postalCode];
/*
implement your http-request code here using the zip string
there are various ways to do this
but two ways your result will arrive...
1 - as a delegate callback
so you would implement the relevant delegate method
(in this same viewController) to use the result
2 - as a completion block
so your result-using method would be that block
*/
}];
[self.locationManager stopUpdatingLocation];
}
In delegation you would have one controller (could be your view controller) that conforms to both protocols, the location manager's protocol and the protocol defined by the http rquest controller.
the view controller creates both objects and assigns itself as the delegate for both.
It tells the location manger to grab the zip code. Once the manager is done, it sends an appropriate delegate method on the delegate [self.delegate didFindZipCode:code onLocationManager: self]. As the delegate is the view controller, it implements this method
-(void)didFindZipCode:(NSString *)code onLocationManager:(MyLocationManager *)manager
{
[self.httpRequestController sendZipCode:code];
}
and the request controller will inform the view controller in a similar way as soon as the desired data is available.
actually blocks would be dealing with this in a similar way — just that no delegate is set, that should be called, but that a code is passed around, that will be called as soon as something happened.
There is a wonderful library available, called AFNetworking, which is very easy to implement.
It uses blocks, which greatly simply communication of data between classes (does away with delegates).
I have been reading, googling and watching Lynda videos to find the answer for this the last couple days. I haven't found a good answer yet.
This seems like it should be pretty simple. With normal methods I can pass variables. But with IBAction being (void) I cant figure out how to get a variable to another method.
Here are some simple examples of what I would like to do:
- (IBAction)treeButton:(id)sender {
int test = 10;
}
-(void)myMethod{
NSLog(#"the value of test is %i",test);
}
This what I really want to have work. I am try to have a button set the initial location that I want to store and use in another method.
- (IBAction)locationButton:(id)sender {
CLLocation *loc1 = [[CLLocation alloc]
initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
}
-(void)myMethod{
NSLog(#"the value of test is %i",test);
NSLog(#"location 1 is %#",loc1);
}
Any suggestions to lead me in the right direction would be great. I have read and watched videos on variable scope, instance varaibles etc. Just not understanding what I need to do here
Change myMethod to accept the parameters you need:
- (void)myMethod:(CLLocation *)location {
NSLog(#"location 1 is %#", location);
}
Invoke it something like so:
- (IBAction)locationButton:(id)sender {
CLLocation *loc1 = [[CLLocation alloc]
initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
[self myMethod:loc1];
}
If you need it to be accessible by multiple methods or at different points in the code, I recommend creating an instance variable for loc1 in your #interface declaration.
#interface MyClass : NSObject {
CLLocation *loc1;
}
In your method, instead of re-declaring it, you'd just set it:
loc1 = [[CLLocation alloc]
initWithLatitude:_locationManager.location.coordinate.latitude
longitude:_locationManager.location.coordinate.longitude];
In myMethod, just access it:
- (void)myMethod{
NSLog(#"location 1 is %#", loc1);
}
Currently i am working on a Location based application for iPhone/iPad . I have several annotations in my MapKit , what i want to do is to track the location of the user and shows the annotations that are within the 3km . Can somebody give me a start ?
Sorry for the delayed response... the question just fell off my radar.
I'm going to suppose that you have a method that returns a set of NSValue-wrapped CLLocationCoordinate2D structs (the basic approach is the same regardless of what your internal data representations are). You can then filter the list using a method something akin to the following (warning: typed in browser):
NSSet *locations = ...;
CLLocation centerLocation = ...; // Reference location for comparison, maybe from CLLocationManager
CLLocationDistance radius = 3000.; // Radius in meters
NSSet *nearbyLocations = [locations objectsPassingTest:^(id obj, BOOL *stop) {
CLLocationCoordinate2D testCoordinate;
[obj getValue:&testCoordinate];
CLLocation *testLocation = [[CLLocation alloc] initWithLatitude:testCoordinate.latitude
longitude:testCoordinate.longitude];
BOOL returnValue = ([centerLocation distanceFromLocation:testLocation] <= radius);
[testLocation release];
return returnValue;
}
];
With the filtered set of coordinates in hand, you can create MKAnnotation instances and add them to the map in the usual manner, as described in Apple's documentation.
If you have many thousands of test locations then I suppose this approach could start to incur performance issues. You would then want to switch your point storage approach to use, e.g., quadtrees, to reduce the number of points that need to be precision-filtered. But don't optimize prematurely!
Hope that helps!
I'm trying to create then retrieve an array of CLLocationCoordinate2D objects, but for some reason the array is always empty.
I have:
NSMutableArray *currentlyDisplayedTowers;
CLLocationCoordinate2D new_coordinate = { currentTowerLocation.latitude, currentTowerLocation.longitude };
[currentlyDisplayedTowers addObject:[NSData dataWithBytes:&new_coordinate length:sizeof(new_coordinate)] ];
I've also tried this for adding the data:
[currentlyDisplayedTowers addObject:[NSValue value:&new_coordinate withObjCType:#encode(struct CLLocationCoordinate2D)] ];
And either way, the [currentlyDisplayedTowers count] always returns zero. Any ideas what might be going wrong?
Thanks!
To stay in object land, you could create instances of CLLocation and add those to the mutable array.
CLLocation *towerLocation = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
[currentDisplayedTowers addObject:towerLocation];
To get the CLLocationCoordinate struct back from CLLocation, call coordinate on the object.
CLLocationCoordinate2D coord = [[currentDisplayedTowers lastObject] coordinate];
As SB said, make sure your array is allocated and initialized.
You’ll also probably want to use NSValue wrapping as in your second code snippet. Then decoding is as simple as:
NSValue *wrappedCoordinates = [currentlyDisplayedTowers lastObject]; // or whatever object you wish to grab
CLLocationCoordinate2D coordinates;
[wrappedCoordinates getValue:&coordinates];
You need to allocate your array.
NSMutableArray* currentlyDisplayedTowers = [[NSMutableArray alloc] init];
Then you can use it. Be sure to call release when you are done with it or use another factory method.
I had currentlyDisplayedTowers = nil which was causing all the problems. Also, the previous advice to init and alloc were necessary. Thanks everyone for the help!
For anyone else with this issue, there's another solution if you are planning on using MapKit.
(The reason I say IF, of course, is because importing a module such as MapKit purely for a convenient wrapper method is probably not the best move.. but nonetheless here you go.)
#import MapKit;
Then just use MapKit's coordinate value wrapper whenever you need to:
[coordinateArray addObject:[NSValue valueWithMKCoordinate:coordinateToAdd]];
In your example..
[currentlyDisplayedTowers addObject:[NSValue valueWithMKCoordinate:new_coordinate]];
I will try to make myself as clear as possible. Let start from the beginning. I have an application with a tableview that contains a list of places with distances from myLocation. Now everytime I get an update in the gps location I run the following code
- (void)locationUpdate:(CLLocation *)location {
myLocation = location;
for (Trek * trek in list) {
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[trek latitude_start] longitude:[trek longitude_start]];
double dis = [locationManager getDistance: loc];
[trek setDistance:dis];
[trek setDistanceUnit];
[loc release];
}
[self.tableView reloadData];
}
Now this piece of code [trek setDistanceUnit]; calls
-(void) setDistanceUnit {
if (self.distance < 1000.0)
self.distanceString = [NSString stringWithFormat:#"%.0lf m", self.distance];
}
Now if I use only distanceString the application crash. Now I think it may have something to do with the fact that those updates may run concurrently (in parallel) to the access required by the view to draw the cells. Anyone has any idea? I can post more code if helpful, I just didn't want to post too much to make this post too long.
I tried to search everywhere but I could not found anything so far.
Thanks in advance,
Umberto
PS Now the application is working but I would like to understand what is going on.
If your distanceString is a retain property, assigning it without self sets it up for a crash because you bypass the setter, and assign the string without retaining it. So when the string gets deallocated on being sent to the autorelease pool, your app crashes.
By synthesizing the accessors using #synthesize and using the dot notation (or setDistanceString:), the object will retain the string for you so that it always has a pointer to it for itself (until it's released).