How to wait for location manager for the current location? - iphone

I am developing an iPhone application in which I want to show nearest restaurants based on the current location
For that In the applicationDidFinishLaunching I am doing this :
self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
NSURL *url = [[NSURL alloc] initWithString:#"http://192.168.0.150/server1/Service.asmx/nearest?lat1=23.013163&lon1=72.559068"];
NSMutableURLRequest* request2=[NSMutableURLRequest requestWithURL:url];
[request2 setHTTPMethod:#"GET"];
[request2 setTimeoutInterval:10];
NSURLResponse *response=nil;
NSError *err=nil;
NSData *data1=[[NSURLConnection sendSynchronousRequest:request2 returningResponse:&response error:&err] retain];
if(data1 == nil)
{
UIAlertView* alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"The network is not available.\n Please check the Internet connection." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:data1];
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
#try {
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
}
#catch (NSException * e) {
NSLog(#"Exception in parsing %# %#",[e name], [e reason]);
}
}
The problem scenario.
the location manager start updating the location
The webservice gets executed before that so I can't get the location values .
I I am putting the web service call in the delegate method then the application launches before the web service gets executed.
in the delegate method I am setting the latitude and longitude in the appropriate strings.
The Problem is that how ensure that the service will not be called until the location manager updates that location and then pass the location to the web service and then call that web service ..

CLLocationManaged has the delegate method.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
it will be called when CLLocationManager will receive some coordinates. Or
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
it will be called when locationManager cannot receive any coordinates. Or when user don't allow to find current location. Also you should call stopUpdatingLocation if you don't want to receive more accurate results.
So you can make your request inside delegate method to be sure is will be called only after updating current location.

One thing I'd recommend is to do your urlRequest in a thread instead as hinted Sixten Otto.
I would setup the locationManager in viewDidLoad or viewDidAppear like you have. Then there are two ways I would call the urlrequest:
Have the request be performed in didUpdateToLocation delegate, then you will know that your urlrequest will only execute after the location is found. This is the suggestion that Morion made.
The other way is to have a notification in the didUpdateToLocation delegate so that when the location is found, it notifies a function to perform the urlRequest.Look up this Tutorial for setting up notifications, it is very helpful and good to know for a lot of programs.
Also, as I mentioned before, you should perform an urlrequest in a thread. The reason is, your request could be locked up and your user would have no control to exit the request. To do this, Setup an NSOperation and place it in the NSOperationQueue:
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget: self
selector: #selector(METHOD:)
object: OBJECTorNIL;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
for more threading info, look up this Tutorial

Related

Message sent to deallocated instance in iPhone

I am new to iPhone,
I am creating NSURLConnection as suggested by apple here
but my app crashes when i Dismiss my view, i have tried concept of NSZombieEnabled which shows me -[CALayer release]: message sent to deallocated instance 0x68b8f40
I am displaying a webpage in Webview, When users clicks on download link in the webview then shouldStartLoadWithRequest method will be called inside this method i am creating NSURLConnection.
here is my code snippet,
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data1
{
[receivedData appendData:data1];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
DirPath=[self applicationDocumentsDirectory];
NSLog(#"DirPath=%#",DirPath);
[receivedData writeToFile:DirPath atomically:YES];
UIAlertView* Alert = [[UIAlertView alloc] initWithTitle:#"Download Complete !"
message:nil delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[Alert show];
[Alert release];
// release the connection, and the data object
[connection release];
[receivedData release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error1
{
[connection release];
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error1 localizedDescription],
[[error1 userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
//CAPTURE USER LINK-CLICK.
Durl=[[url absoluteString]copy];
//Checking for Duplicate .FILE at downloaded path....
BOOL success =[[NSFileManager defaultManager] fileExistsAtPath:path];
lastPath=[[url lastPathComponent] copy];
if (success) //if duplicate file found...
{
UIAlertView* Alert = [[UIAlertView alloc] initWithTitle:#"This FILE is already present in Library."
message:#"Do you want to Downlaod again ?" delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Yes",#"No",nil];
[Alert show];
[Alert release];
}
else //if duplicate file not found directly start download...
{
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:Durl]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
receivedData = [[NSMutableData data] retain];
} else {
NSLog(#"Inform the user that the connection failed.");
}
return YES;
}
Any help will be appreciated.
Make sure that in your implementation of dealloc you are resetting the delegate to nil. Another place for doing so would be viewWillDisappear:.
The reason for your app to crash / access a zombie is that the UIWebView instance will possibly be trying to call back the viewController even though it has already been deallocated. To prevent that, you have to set the delegate of that UIWebView back to nil before the viewController goes out of scope. That is a general issue when working with delegation prior to iOS5's ARC implementation. iOS5 finally offers weak references, those actually nil themselves once their instance is getting deallocated.
Example A:
- (void)dealloc
{
[...]
_webView.delegate = nil;
}
Example B:
- (void)viewWillDisappaer:(BOOL)animated
{
[super viewWillDisappaer:animated];
_webView.delegate = nil;
}
Edit:
After reading your question once again, I realised that the zombie is a UIView or a UIControl since the message is sent to a CALayer. Make sure your problem actually is related to the web view by temporarily removing all webView related code.
I think issue with this NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
You are creating an instance of NSURLConnection with delegate self, when you dismiss the view everything get deallocated on that view. But when the NSURLConnection tries to call it's delegate method crash will occur.
So you need to set the delegate of NSURLConnection to nil in your viewWillDisappear for doing this, you need to create object of NSURLConnection in interface.
#interface yourClass
{
NSURLConnection *theConnection;
}
#end
in .m
theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
- (void)viewWillDisappaer:(BOOL)animated
{
[super viewWillDisappaer:animated];
theConnection.delegate = nil;
}

nearby venue to iphone into simple array

Im really having a hard time figuring this out. Ive read a bunch of PDFS and stackoverflow questions on this but I have never used and API and can't quiet get it.
I am trying to get my longitude and latitude coordinates and use any API out there (foursquare, google maps, any others you can recommend that are free?) to get a list of nearby parks and just put it into an NSMutableDictionary key=name object=#"distance". No need to get all its content, just distance and name. But I have been stuck on the first part, getting my longitude and latitude coordinates for over 4 hours. Can anyone show me code wise how I would get my coordinates, no need to explain how to parse the API, once i have my coordinates I feel like I can figure that out. Ive downloaded apples locateme source code but still cant get it to work on mine. Is there maybe a set of easy to follow steps or code someone can provide that I can just use and get this headache over with? Ive imported the location framework. Is there a quick 10-20 lines of code to solve this, not 3 additional view controllers with so much I dont quiet understand.
Thanks a lot
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
#pragma mark Current location methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
latit = newLocation.coordinate.latitude;
longit = newLocation.coordinate.longitude;
NSLog(#"latitude = %f",latit);
NSLog(#"longitude = %f",longit);
[manager stopUpdatingLocation];
[self getNearByList];
}
-(void)getNearByList
{
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyyMMdd"];
NSString *currentDate = [dateFormat stringFromDate:[NSDate date]];
[dateFormat release];
NSURL *url = [NSURL URLWithString:[[NSString stringWithFormat:#"https://api.foursquare.com/v2/venues/search?ll=%f,%f&client_id=YOUR_CLIENT_ID_HERE&client_secret=YOUR_CLIENT_SECRET_HERE&v=%#&limit=100&radius=2000&categoryId=4bf58dd8d48988d1e0931735,4bf58dd8d48988d176941735,4bf58dd8d48988d1ed941735,4bf58dd8d48988d119951735,4bf58dd8d48988d123941735,4d954afda243a5684865b473,4edd64a0c7ddd24ca188df1a,4bf58dd8d48988d1c9941735,4bf58dd8d48988d1bd941735,4bf58dd8d48988d124951735,4bf58dd8d48988d115951735,4bf58dd8d48988d11a951735,4bf58dd8d48988d10c951735,4bf58dd8d48988d11b951735,4bf58dd8d48988d11e951735,4bf58dd8d48988d1f9941735,4bf58dd8d48988d1f5941735,4bf58dd8d48988d113951735,4f04afc02fb6e1c99f3db0bc,4bf58dd8d48988d110951735,4bf58dd8d48988d1f2941735,4bf58dd8d48988d1fd941735,4bf58dd8d48988d103951735,4bf58dd8d48988d104941735,4f04aa0c2fb6e1c99f3db0b8,4d1cf8421a97d635ce361c31,4bf58dd8d48988d1f8941735,4d4b7105d754a06374d81259,4bf58dd8d48988d16d941735,4bf58dd8d48988d128941735,4bf58dd8d48988d111951735,4bf58dd8d48988d1ca941735,4bf58dd8d48988d117951735,4bf58dd8d48988d107951735,4bf58dd8d48988d1fa941735,4bf58dd8d48988d118951735,4bf58dd8d48988d17f941735,4bf58dd8d48988d1ac941735,4bf58dd8d48988d180941735",latit,longit,currentDate] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; //YOU CAN FOUND MORE CATEGORY ID AT FOURSQURE WEBSITE..
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval: 30.f];
NSLog(#"url = %#",urlRequest);
webData1 = [[NSMutableData data] retain];
urlConnection = [[NSURLConnection alloc] initWithRequest: urlRequest delegate: self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData1 setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData1 appendData:data];
//NSLog(#"webData1 = %#",webData1);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"Error"
message : #"An error has occured."
delegate:nil
cancelButtonTitle :#"OK"
otherButtonTitles :nil];
[alert1 show];
[alert1 release];
[webData1 release];
[connection release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *data = [[NSString alloc] initWithBytes: [webData1 mutableBytes] length:[webData1 length] encoding:NSUTF8StringEncoding];
NSLog(#"data = %#",data);
[connection release];
[webData1 release];
}
Use Google Place Api.You just need to register and than you will get key for api
//example api. This api will give you food in your defined radius of longitude and latitude in the json data format
https://maps.googleapis.com/maps/api/place/search/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=AddYourOwnKeyHere
Google Place API
Hope, this will help you..enjoy...

memory leak with NSMutableData

I have a class for connecting with httprequests. I am getting a memory leak for "NSMutableData" altho I am releasing it in "didFailWithError" and in "connectionDidFinishLoading" of the connection object:
- (BOOL)startRequestForURL:(NSURL*)url {
[url retain];
NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc] initWithURL:url];
// cache & policy stuff here
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPShouldHandleCookies:YES];
NSURLConnection* connectionResponse = [[[NSURLConnection alloc] initWithRequest:urlRequest delegate:self] autorelease];
if (!connectionResponse)
{
// handle error
return NO;
} else {
receivedData = [[NSMutableData data] retain]; // memory leak here!!!
}
[url release];
[urlRequest release];
return YES;}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error {
UIAlertView *alert =
[[[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"Connection problem", nil)
message:NSLocalizedString(#"A connection problem detected. Please check your internet connection and try again.",nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil, nil]
autorelease];
[alert show];
[connectionDelegate performSelector:failedAction withObject:error];
[receivedData release];}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection {
[connectionDelegate performSelector:succeededAction withObject:receivedData];
[receivedData release];}
The static analyser will call this a leak because you are not guaranteeing that either of the methods featuring a release will actually be called.
If you set receivedData as a retained property, and do
self.receivedData = [NSMutableData data];
Then in your dealloc (and also your didFail and didFinish, instead of the release):
self.receivedData = nil;
You will be OK.
As jbat100 points out, you are also leaking url and urlRequest if the !connectionResponse, unless you have omitted this code from the question
You need to make really sure that these two delegate methods are the only possible way the request could finish. I can see a leak here
if (!connectionResponse)
{
// handle error
return NO;
}
you do not do the release operations
[url release];
[urlRequest release];
Which you do when the connectionResponse is non-nil. On another note I strongly suggest the ASIHTTP Obj C library for doing this type of stuff.
if you want remove this leak take NSURLConnection in .h file and release that in connectionDidFinishLoading method .reason is you are allocted NSURLConnection object there but you cann't release over there if release app kill over there .that why you have to create NSURLConnection object in .h
Why do you think you are leaking? (NSMutableData) If it is because of Xcode's Analyze option; well, it lies, as it can't handle even such obvious complex situations.
However, as Narayana pointed out, you are also leaking the connection, which you should release in both the finish and fail delegate methods.

iphone-uialertview-thred

in iphone,
i call one webservice For login checking...
When Application Is Underprocess ,, I Show UIAlertview With UIActivityIndicatorView
using thread,,
now i want to enable cancel button ,, means during the process if i want to cancel that process,, then my apps teminates webservice calling
but when i enable cancel button then ERROR OCccur,
Any One Can Help
My COde Is
-(NSMutableString*) getLoginMessage:(NSString*) UserName : (NSString *) Password
{
[NSThread detachNewThreadSelector:#selector(showAlertMethod) toTarget:self withObject:nil];
NSArray *Keys =[[NSArray alloc] initWithObjects:#"LoginName",#"PassWord",nil];
NSArray *KeyValue =[[NSArray alloc] initWithObjects:UserName,Password,nil];
operationName=[[NSString alloc] init];
operationName =#"ClientLogin";
NSString *StrService=[[NSUserDefaults standardUserDefaults] objectForKey:#"WebService"];
NSURL *WebServiceUrl=[WebServiceHelper generateWebServiceHTTPGetURL:StrService : operationName : Keys :KeyValue];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:WebServiceUrl];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser setDelegate:self];
[parser parse];
[Keys release];
[KeyValue release];
[StrService release];
[WebServiceUrl release];
//[parser release];
[NSThread detachNewThreadSelector:#selector(dismissAlertMethod) toTarget:self withObject:nil];
return Result;
}
-(void)showAlertMethod
{
NSAutoreleasePool *pool1=[[NSAutoreleasePool alloc]init];
progressAlert = [[UIAlertView alloc] initWithTitle:#"Loging in...\nPlease wait...\n" message:#"" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
CGRect alertFrame = progressAlert.frame;
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.frame = CGRectMake(135,alertFrame.size.height+75, alertFrame.size.width,30);
activityIndicator.hidden = NO;
activityIndicator.contentMode = UIViewContentModeCenter;
[activityIndicator startAnimating];
[progressAlert addSubview:activityIndicator];
[activityIndicator release];
[progressAlert show];
[pool1 release];
}
-(void)dismissAlertMethod
{
NSAutoreleasePool *pool2=[[NSAutoreleasePool alloc]init];
[progressAlert dismissWithClickedButtonIndex:0 animated:YES];
[pool2 release];
}
There are some major flaws in how you attack the problem. Firstly you should not detach new threads to show and hide the alert view, all UIKit classes must be called form the main thread (only few documented exceptions exist).
What you want is an API designed to be asynchronous for dispatching the login request. I would suggest you use an Sync-Async pattern for this. I have written a longer blog post on this topic here: http://blog.jayway.com/2011/04/28/sync-asyn-pair-pattern-easy-concurrency-on-ios/
In essence I believe you want two public methods:
-(NSString*)loginMessageWithName:(NSString*)name
password:(NSString*)password
error:(NSError**)error;
-(NSOperation*)loginMessageWithName:(NSString*)name
password:(NSString*)password
delegate:(id<LoginMessageDelegate>)delegate;
The first method is synchronous, implement it as straightforward as you like, no threads on any thing, just make it work.
The second method is a wrapper that instantiates a NSOperation objects and puts it on some queue. Returning the operation allows you to cancel it, but the result will be returned on the delegate. The delegate will probably need to look something like this:
#protocol LogonMessageDelegate <NSObject>
-(void)didReceiveLoginMessage:(NSString*)message;
-(void)failedLoginMessageWithError:(NSError*)error;
#end
The implementation of loginMessageWithName:password:delegate: is very straight forward:
NSOperation* op = [[LoginMessageOperation alloc] initWithName:name
password:password
delegate:delegate];
[myOperationQueue addOperation:op];
return [op autorelease];
Most of the work will be done in your NSOperation subclass' main method. This is where you call the synchronious implementation, check for cancelation, and call back to the delegate if needed. Probably something like this:
-(void)main {
NSError* error = nil;
NSString* message = [logonMessageManager logonWithName:name
password:password:
error:&error];
if (![self isCancelled]) {
if (message) {
[delegate performSelectorOnMainThread:#selector(didReceiveLoginMessage:)
withObject:message
waitUntilDone:NO];
} else {
[delegate performSelectorOnMainThread:#selector(didReceiveLoginMessage:)
withObject:error
waitUntilDone:NO];
}
}
}
Then setup and handle the alert view on the main thread. Call [operation cancel] if the user cancels, or dismiss the alert when the delegate receives a callback.

EXC_BAD_ACCESS issue on iphone and simulator

I am getting an EXC_BAD_ACCESS out side of my own code. Currently my code gets a URL through a shareURLCache object and then starts url connection. Once I leave the method that starts the url connection I hit the EXC_BAD_ACCESS. I have tried using instruments to find any zombies and I have analysed for memory leaks and not turned up either. At this point I am completely stuck.
Here is the code that loads the url and starts the url connection
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"At new location: %#",newLocation);
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance([newLocation coordinate], 750, 750);
[mapView setRegion:region animated:YES];
[location stopUpdatingLocation];
CLLocationCoordinate2D coord = [newLocation coordinate];
NSURL *url = [urlCache getReccomendationForUID:#"12345" atLat:coord.latitude
atLon:coord.longitude forCategories:nil];
// Create the request.
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (connection) {
// Create the NSMutableData to hold the received data.
// xmlData is an instance variable declared elsewhere.
xmlData = [[NSMutableData alloc]init];
} else {
NSLog(#"Could not create connection");
}
}
Method from the sharedURLCache that returns the url
-(NSURL *)getReccomendationForUID:(NSString *)u atLat:(double)lat atLon:(double)lon forCategories:(NSArray *)cat
{
if(remote) {
NSMutableString *categories = [[NSMutableString alloc]init];
for(NSString *s in cat) {
[categories appendString:#"&cat="];
[categories appendString:s];
}
NSString *s = [NSString stringWithFormat:#"%#/recommendation?uid=%#&psw=null&lat=%f&lon=%f?%#",
apiRoot,u,lat,lon,categories];
[categories release];
return [NSURL URLWithString:s];
} else {
return [[NSBundle mainBundle] URLForResource:#"XMLTest" withExtension:#"xml"];;
}
}
Just start by commenting out code and running to see if you can get the mem error to disappear then start adding code again until it appears, then you have a better idea where the issue is. it could be anywhere in your code since you seem to have a number of objects in there that are not passed in e.g. 'location'.
[location stopUpdatingLocation];
I had same memory issue with
[mapView setRegion:region animated:YES];
This method doesn't like fast updates...