MKReverseGeocoder server returned error: 503 - iphone

Currently i am developing an iPhone application where i have to show user's current city and location for which i am using Mapkit Framework.When i build the application it works fine and show me the exact city details .But right now when i try to build the application again application shows following error message in my log
/SourceCache/ProtocolBuffer_Sim/ProtocolBuffer-26/Runtime/PBRequester.m:523 server returned error: 503
reverseGeocoder: didFailWithError:Error Domain=PBRequesterErrorDomain Code=6001 "Operation could not be completed. (PBRequesterErrorDomain error 6001.)"
Is any body facing the same issue and how can i resolve it?

I am pretty sure this is happening because you are in testing, and using the reverse geocoder too much and Google's servers know that. So, it has basically blocked you for a while. Try again later and see if it works.
You need to make sure that you are not calling the geocoder more than once every 60 seconds.

I find out!
Well, now we'll have to use CLGeocoder, but if you want still to use MKReverseGeocoder, you MUST not call [geocoder start] twice, even if the geocode object is a fresh new one!
For example, DON'T do this:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
MKReverseGeocoder *geoCoder = [[[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate] autorelease];
geoCoder.delegate = self;
[geoCoder start];
}
Or you'll get an arror: the location manager update position function is being called as soon as a new position is detected. As the accuracy is getting better and better, a new fresh new posistion is being sent to "didUpdateToLocation".
But creating a new object MKReverseGeocoder each time a position is found is a bad idea!
So, you've got a few solutions:
- Put a boolean that is true when geocoder is started. Then in didFindPlacemark (geocoder's), you should stop the geocoder with [geocoder cancel] and set your boolean to false.
- Make geocoder variable not local and manange a [geocoder cancel] + realease and create a new one and[geocoder start] each time didUpdateToLocation is beeing called.
- Any other way to avoid [geocoder start] to be called twice
I used the first solution and never get the 503 error anymore.

For me, MKReverseGeocoder was failing with 503 far too many times. It would also fail the first time it was requested, well after 60 seconds had passed. As a result, I decided to give up using it and instead decided to access Google's API directly using NSURLRequest via a service I created that also parses the result as a JSON String using the SBJSON Framework (very useful).
From my service, I call the following URL as follows:
NSString *urlStr = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=true", coordinate.latitude, coordinate.longitude];
where coordinate is a CLLocationCoordinate2D.
I realise this is a long way around the problem, but since converting to this system I have had no issues!

It can happen at random, depending on the server's status.

Related

Geocoding address into coordinates in iPhone

I am trying to geocode address into coordinates using following code:
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:#"6138 Bollinger Road, San Jose, United States" completionHandler:^(NSArray* placemarks, NSError* error){
for (CLPlacemark* aPlacemark in placemarks)
{
// Process the placemark.
NSString *latDest1 = [NSString stringWithFormat:#"%.4f",aPlacemark.location.coordinate.latitude];
NSString *lngDest1 = [NSString stringWithFormat:#"%.4f",aPlacemark.location.coordinate.longitude];
lblDestinationLat.text = latDest1;
lblDestinationLng.text = lngDest1;
}
}];
I have tried it many times but the debugger never enters the block and I am not able to get the location. What can I try next?
All right I found my mistake.
The code is correct and works perfect. All the while I was working on it was through debugger and was trying to figure out why the debugger did not enter the block. But now I have found out debugger does not enter the block at that moment. It takes little in getting the location values. It is done asynchronously so I was not able to find it and I was getting crash because of no values just after the crash. I have moved my code post block to inside the block and everything works fine for me now.
I just ran that exact code and it worked as expected. Make sure that you have an active internet connection.
Try adding a NSLog on the strings and see if it gets called.
NSLog(#"lat: %#, lng: %#", latDest1, lngDest1);
Are you running it in the simulator or the device?
Blocks are new features to Objective C from iOS4.0 onwards. A block you can imagine as a delegate method working in same functional block. As for any delegate method it takes time to invoke, depending upon the condition, same way block executes the code inside it, when it completes its work of geocoding. You can read more about Block in apples documentation or read http://www.raywenderlich.com/9438/how-to-use-blocks-in-ios-5-tutorial-part-2.
You can also have look into my repository on GITHUB https://github.com/Mangesh20/geocoding

Force location update

I'm attempting to overcome a sometimes-failure of didUpdateToLocation when checking local data based on current position, closing the app, traveling a bit, and opening the app again. What happens is that the user visits one place, checks the list, goes to another place, and the list is updated but using the old location data.
I would like to make sure I have a fresh newLocation.
What's wrong with this code?
double aa,bb,cc;
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
//old data? retry.
aa=[newLocation.timestamp timeIntervalSinceReferenceDate];
bb=[NSDate timeIntervalSinceReferenceDate];
cc=bb-aa; //must be <60 - minute-fresh
if (cc>60) {
[manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
[manager startUpdatingLocation]; //only stop if new reliable pos fetched.
return;
}
...handle position
}
The symptoms are that cc is about 1200 seconds on app start, then on each retry it increases a few seconds.
I've tried -[newLocation.timestamp timeIntervalSinceNow], and similarly it increases a few seconds at each retry. At one point the interval was ~2400.
I'm using FilterNone and AccuracyBest, if that could influence it.
I'm open to alternative code solutions to make sure you have a fresh position.
The answer was that you need to write the handling the way you want it to behave.
I've read up on this common problem. I should have clarified that "force" means to start unambiguous behavior that gives a reliable position under optimal conditions for the phone. Not to busy-wait until satisfied or to expect an immediate result/error code.
From a common sense viewpoint, what would be desirable by all developers would be at least an extra method to simply ask for a position within parameters, and callback only when it's valid and within accuracy, or canceled, or timed out. If the conditions prevent it you then don't need to test out esoteric behavior to be able to handle it with custom code.
Why I needed to ask about this at all was:
no existence of a method functioning as described above
using code from a book (More Iphone 3 Development)
when writing it from scratch (looking at LocateMe.xproj), discovering that:
simulator behavior differs from phone behavior (not talking about the position itself, which is obviously as good as ip lookup can make it, but the behavior of didUpdateToLocation). Recognizing the limitations of a simulator, the method should at least behave like they do on a device. But currently, correctly written location handling/checking code just times out in the simulator (as in the LocateMe example), while incorrect code (asking once and using newLocation on callback) works.
and a bug causing didUpdateToLocation being called twice after [locationManager stopUpdatingLocation];
If on top of this you (like I) load data based on your position, and the data is required by multiple views in your application, the behavior of Apple's location-fetching methods doesn't make it easy to handle the chain of update-load-calculate-present consistently and problem-free throughout the app. Especially if your stuck between user/boss perception or decision of how it should work (a rock) and how the system works (a hard place).
Here's my current code which works on a device and in a simulator:
//ask for a position, as fresh as possible.
-(void)updateMeMap {
lastloc.coordinate=homeloc.coordinate;
lm.delegate=self;
ctr=0;
[self performSelector:#selector(stopUpd) withObject:nil afterDelay:gpstimeout];
[lm startUpdatingLocation];
}
//called on each position update.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
ctr++;
if (ctr<15) {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"%d",ctr);
if (locationAge<60) {
NSLog(#"Found");
ctr=40;
homeloc.coordinate=newLocation.coordinate;
[self stopUpd];
[self reload];
} else {
NSLog(#"Lastupd");
lastloc.coordinate=newLocation.coordinate;
}
} else {
//enough tries, if not canceled choose lastloc.
if (ctr<40) {
NSLog(#"Last");
ctr=40;
homeloc.coordinate=lastloc.coordinate;
[self stopUpd];
[self reload];
}
}
}
//force stop updates. ctr prevents extra calls after stopUpdatingLocation.
//called after the timeout delay, if position found, cancel the timeout.
-(void)stopUpd {
[lm stopUpdatingLocation];
lm.delegate=nil;
if (ctr<15) {
ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
NSLog(#"Timeout");
homeloc.coordinate=lastloc.coordinate; //#need "copy"?
[self reload];
} else {
ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(stopUpd) object:nil];
}
}
// "couldn't get userlocation" handler. I also cancel like this on connectionDidFailWithError.
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Location failed: %#",[error localizedDescription]);
ctr=0;
[self stopUpd];
}
Where ctr is there to prevent the 2 extra calls, lastloc is last known reliable position, homeloc is the phone position used for (threaded) loading of location-specific data with [self reload].
The constants 15 and 60 are safe values from real-world testing; gpstimeout is set to 30. If you work a lot in a simulator you may want to set it to something short like 3 seconds, as all you will get is a stale but relatively usable position and no more until the timeout.
Edit: If you can best my code or point out an omission, I'll mark that as answer, I hate marking my own as answer.
I've come across a similar problem in one of my previous apps.
There's no way to force a location update as far as I'm concerned - (I searched for a long time and didn't find anything)
One thing that I found was using the UIBackgroundModes key in my info.plist.
Support for some types of background execution must be declared in advance by the application that uses them. An application declares this support by including the UIBackgroundModes key in its Info.plist file. Its value is an array that contains one or more strings with the following values:
audio. The application plays audible content to the user while in the
background. (This includes streaming audio or video content using
AirPlay.)
location. The application keeps users informed of their
location, even while running in the background.
voip. The application
provides the ability for the user to make phone calls using an
Internet connection.
Which is what you're looking for. See the docs for more info.
What if you put more of the code within the age check, like:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge<60) {
[manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
...handle position
}
}

stop location updating on iPhone

I am using following code to stop location updating
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
But still after calling thing function the location services are not stopped and still tries to find the location , can any one help me what I have done wrong.
thanks in advance.
Hopefully the following link could help you I guess.
http://www.iphonedevsdk.com/forum/iphone-sdk-development/2299-cllocationmanager-stopupdatinglocation-not-working.html
I had the same problem when it wouldn't stop updating location. I didn't try to nil the delegate though, because the problem was that in my "locationManager:didUpdateToLocation:fromLocation:" method was called other method before actually stopping updating location, i called my own method (download objects from server). It was okay until i had to download too many. I guess the deal is that it tries to download them too long for "didupdatelocation" to be called over and over again.
I thought of two solutions for that (for me at least):
Do stuff AFTER stopping manager. - That didn't work for some reason, i still had multiple calls.
Do stuff asynchronously. - That seemed to work well for me.
I hope this helps.
Normally the code you used [locationManager stopUpdatingLocation]; should work for stop updating location. But if that won't work then you can have one alternative soltion as follow:
-(void)viewDidLoad
{
firstTime = TRUE;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if(firstTime = TRUE)
{
firstTime = FALSE;
current_Latitude=newLocation.coordinate.latitude;
current_Longitude= newLocation.coordinate.longitude;
}
}
Here you can use one BOOL variable to check whether you updated the location or not.

issues with geting location coordinate time to time

time to time there is an issue with geting the location coordinate on my app.
I have been testing my app for location coordinate from the simulator and the iphone sitting at my home (it is not just my home, i tested it in different location (outdoor) as well with a very good network connectivity), and i see this wired behavior, i have the right co ordinate at the moment and then i send the app to the background and bring it back i get the right location co ordinate, and if i do it 8-10 times (i.e sending it to background and bringing it to foreground) once in a while after the app comes from the background i cannot get location co ordinate, the only way to get the location co ordinate at this moment is to kill the app and then start fresh. So i am sure some thing is going wrong but I am not sure what is it.
This is what I am doing
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//if the time interval returned from core location is more than 30 seconds we ignore it because it might be from an old session
if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 30) {
if(newLocation.coordinate.latitude != previousLocation.coordinate.latitude && newLocation.coordinate.longitude != previousLocation.coordinate.longitude){
if(newLocation.horizontalAccuracy <= 100){
[self.locationManager stopUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
}
else{
[self.locationManager startUpdatingLocation];
}
So basically i take the newLocation only if it is not older then 30 sec, and it is not same as previous location that i have stored locally and the horizontal accuracy is less than 100 meter. When i run it in debugger what i am observing is i get to the first if condition 3-4 times and if it fails it doesn't come after that, which means didUpdateToLocation doesn't get called at all.
Once the co ordinate meet all my criteria I do stopupdatinglocation and do startMonitoringSignificantLocationChanges.
The reason i am doing startUpdatingLocation in my else block is.
For example if didUpdateToLocation got called due to the startMonitoringSignificantLocationChanges, i want to get the accurate location after that so i am doing startUpdatingLocation every time i don't get the right location that i am looking for as i believe doing multiple startUpdatingLocation doesn't harm anything.
Let me know if there is something wrong in my thought process or in the code logic.
The first thing I would check is your info.plist. You have to include the key Required Background Modes -> App registers for location updates. Without this you won't receive location updates (besides significant location changes and region monitoring) while in the background.
In the main else, you call startUpdatingLocation. While I don't believe this hurts anything, unless you are balancing it with a stopUpdatingLocation I don't believe it will do anything. Documentation says:
Calling this method several times in succession does not automatically result in new events being generated. Calling stopUpdatingLocation in between, however, does cause a new initial event to be sent the next time you call this met
But either way, I don't think you need to tell it to startUpdating again, it will continue on it's own when the distanceFilter property is exceeded or the hardware gathers a more accurate location reading.
I don't see a closing } for your second if.

MKErrorDomain error 4 iPhone

I keep getting this randomly when I run my gps app I'm building. It doesn't happen everytime, and the coordinates passed in are always valid (i nslog them). Is there documentation for these somewhere?
EDIT:
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(locManager.location.coordinate.latitude, locManager.location.coordinate.longitude);
geocoder1 = [[MKReverseGeocoder alloc] initWithCoordinate:coord];
geocoder1.delegate = self;
[geocoder1 start];
and then about half the time it returns an error. I tried releasing and re-assigning the geocoder if there was an error, but that didn't help. Only thing that did was restarting the app.
In "MKTypes.h" in the MapKit framework, the following is defined:
Error constants for the Map Kit framework.
enum MKErrorCode {
MKErrorUnknown = 1,
MKErrorServerFailure,
MKErrorLoadingThrottled,
MKErrorPlacemarkNotFound,
};
...
MKErrorPlacemarkNotFound
The specified placemark could not be found.
This sounds like you are referencing some unknown placemark in your code? Or it could be that Google doesn't have a name for the position you are passing - however valid the coordinates may be.
I've met and solved this issue recently. In my case, when Apple Map cannot find any result for a query, it sometimes will just throw this this "MKErrorDomain = 4" error. So I ended up just treat this as "result not found".
It was painstaking to find this out, MapKit needs a better Error handling system.
I've been hitting this error repeatedly, and was unable to figure out how to make it stop; but I finally found an end-run around the whole issue that works quite well, and only takes a little more work: Don't use Apple's MKReverseGeocoder at all -- instead, directly call Google's reverse-geocoding API (this is apparently the same service that MKReverseGeocoder does behind the scenes). You can get back either JSON or XML (your preference), which you will then have to parse, but that isn't too hard.
For example, since my app is using ASIHTTPRequest, this is what it looks like (although this would also be easy to do with do with Apple's native APIs such as NSURLConnection):
#pragma mark -
#pragma mark CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// Be careful: My code is passing sensor=true, because I got the lat/long
// from the iPhone's location services, but if you are passing in a lat/long
// that was obtained by some other means, you must pass sensor=false.
NSString* urlStr = [NSString stringWithFormat:
#"http://maps.googleapis.com/maps/api/geocode/xml?latlng=%f,%f&sensor=true",
newLocation.coordinate.latitude, newLocation.coordinate.longitude];
NSURL* url = [NSURL URLWithString:urlStr];
self.reverseGeocoderRequest = [ASIHTTPRequest requestWithURL:url];
self.reverseGeocoderRequest.delegate = self;
[self.reverseGeocoderRequest startAsynchronous];
}
By the way, Google's API has rules, just like Apple's does. Make sure you read the docs, especially regarding quotas.
I'm running into the same thing (the exact same code randomly fails sometimes) and I think I've found the answer. From Apple's developer docs: "Each Map Kit application has a limited amount of reverse geocoding capacity, so it is to your advantage to use reverse geocode requests sparingly."
So my theory is, we're getting rate-limited... since no other variables are changing (i.e. my code isn't changing, I'm running it on the simulator so the location of the device isn't changing, etc.) I think this must be the only remaining reason.
I just got done with a lot of research on this problem and it seems to be outside of our hands. I checked the developer forums as well as all around Stack and elsewhere and no one has a solution other than using a different service. There is a pretty good thread at https://devforums.apple.com/message/154126 on the subject.
Some people find the error after a certain time, I just find it to be out for a while and then comes back. I looked at the "Current Address" sample code and I couldn't see how I might have messed up. I ran the sample code and sure enough, it was NSLogging errors instead of returning a location.
This link has some code using Google's reverse geocoder: http://www.iphonedevsdk.com/forum/iphone-sdk-development/31883-pbrequestererrordomain-errors-reverse-geocoding.html#post155793
Actually, I am running into this problem as well. Code is extremely compact
//1. ask map for current coords
CLLocationCoordinate2D userLocation;
userLocation.latitude = [[_theMapView.userLocation location] coordinate].latitude;
userLocation.longitude = [[_theMapView.userLocation location] coordinate].longitude;
NSLog(#"%f, %f",userLocation.latitude,userLocation.longitude);
//2. reverse geocode coords
MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc]
initWithCoordinate:userLocation];
[reverseGeocoder setDelegate:self];
[reverseGeocoder start];
and later simply NSLog the error in the fail delegate method. It works the first time or two, then stops working