I'm implementing a CLLocationManager right as described in several tutorials.
Everything works fine up to the point where the LocationManager receives a second update. Then a memory leak occurs.
Instruments tells me, that the leaked objects are NSCFTimer, GeneralBlock-16 and NSCFSet
Any ideas?
Thanks for any help
[Edit]
After repeatingly starting and stopping the locationManager, the updated seem to come faster. This makes me think that the CLLocationManager initializes a new timer every time a location-update occurs... VERY strange...
And - so you don't need to read my comment - the app crashes after a while
[Edit]
Ok - I don't get it here's some code...
I'm using a separate class for the locationManager, as described here: http://www.vellios.com/2010/08/16/core-location-gps-tutorial/
locationManager.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#protocol locationManagerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface locationManager : NSObject <CLLocationManagerDelegate>{
CLLocationManager *myLocationManager;
id delegate;
CLLocation *bestEffortAtLocation;
BOOL outOfRange;
}
#property (nonatomic, retain) CLLocationManager *myLocationManager;
#property (nonatomic, retain) CLLocation *bestEffortAtLocation;
#property (nonatomic, assign) id delegate;
#property (nonatomic, assign) BOOL outOfRange;
#end
locationManager.m
#import "locationManager.h"
#implementation locationManager
#synthesize myLocationManager;
#synthesize delegate;
#synthesize bestEffortAtLocation;
#synthesize outOfRange;
- (id) init {
self = [super init];
NSLog(#"initializing CLLocationManager");
if (self != nil) {
outOfRange = NO;
self.myLocationManager = [[[CLLocationManager alloc] init] autorelease];
self.myLocationManager.delegate = self;
self.myLocationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[self performSelector:#selector(stopUpdatingLocation:) withObject:#"Timed Out" afterDelay:100.0];
}else{
NSLog(#"Location Manager could not be initialized");
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if(outOfRange == NO){
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(stopUpdatingLocation:) object:nil];
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
[self.delegate locationUpdate:newLocation];
}else{
[self.myLocationManager stopUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"error!!!!");
[self.myLocationManager stopUpdatingLocation];
[self.delegate locationError:error];
}
- (void)dealloc {
[myLocationManager release];
[bestEffortAtLocation release];
[super dealloc];
}
#end
then, in the main-class I call:
mainFile.h (exerpt)
#import "locationManager.h"
#interface mainFile : UIViewController <locationManagerDelegate , UIAlertViewDelegate>{
locationManager *locationController;
CLLocation *myLocation;
}
#end
mainFile.m (exerpt)
#import "locationManager.h"
#implementation mainFile
#synthesize locationController;
#synthesize myLocation;
- (void)locationError:(NSError *)error{
// Do alert-Stuff
}
- (void)locationUpdate:(CLLocation *)location {
// Do location-Stuff
}
- (void)viewDidLoad
{
[super viewDidLoad];
locationController = [[[locationManager alloc] init] autorelease];
locationController.delegate = self;
[locationController.myLocationManager startUpdatingLocation];
}
- (void)dealloc {
self.locationController = nil;
[locationController release];
}
#end
It's driving me kinda crazy :)
My advice is to not be obsessed with one-time memory leaks that the iOS itself generates. It does this in many places and the leaks are all pretty harmless.
Ah, a long dead problem, I love them.
locationController is an iVar, not a property, so when you create it in viewDidLoad, assigning it to _locationController doesn't take on ownership.
You've autoreleased the object, so next time around the event loop, the auto-release pool is drained and it is released.
You could fix it by making it a retain property ( which would fit with your locationManager = nil ), or getting rid of the auto-release, and using an explicit [locationManager release] in dealloc.
Try doing a Build and Analyze. I usually find memory leaks and other non-syntax errors that way.
Related
I want to get users current location. Here is my code
// In LoginViewController.h
#interface LoginViewController : UIViewController <UserLocationDelegate,UIAlertViewDelegate> {
CLLocation *usersLocation;
}
#property (nonatomic,strong) CLLocation *usersCurrentLocation;
#end
// In LoginViewController.m
#implementation LoginViewController
#synthesize usersCurrentLocation;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.usersCurrentLocation = nil;
[self currentLocationOfUser];
}
-(void)currentLocationOfUser {
UserLocation *userLocation = [[UserLocation alloc]init];//UserLocation];
userLocation.delegate = self;
[userLocation getCurrentLocationOfUser];
}
#pragma mark - User Location Delegate Methods
- (void)locationUpdate:(CLLocation *)location
{
self.usersCurrentLocation = location;
NSLog(#"Latitude:- %.6f",self.usersCurrentLocation.coordinate.latitude);
NSLog(#"Longitude:- %.6f",self.usersCurrentLocation.coordinate.longitude);
}
- (void)locationError:(NSString *)errorMsg
{
[Common showAlertWithTitle:#"Error" andMessage:errorMsg];
}
// In UserLocation.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#protocol UserLocationDelegate <NSObject>
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSString *)errorMsg;
#end
#interface UserLocation : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
__weak id<UserLocationDelegate>delegate;
}
#property (nonatomic,strong) CLLocationManager *locationManager;
#property (nonatomic,weak) id<UserLocationDelegate>delegate;
-(id)initUserLocation;
-(void)getCurrentLocationOfUser;
#end
// In UserLocation.m
#import "UserLocation.h"
#implementation UserLocation
#synthesize locationManager;
#synthesize delegate;
#synthesize geoCodingDelegate;
-(id)initUserLocation
{
if (self == [super init]) {
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
}
return self;
}
-(void)getCurrentLocationOfUser {
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
if ([CLLocationManager locationServicesEnabled]) {
//[self.locationManager startMonitoringSignificantLocationChanges];
[self performSelector:#selector(startLocationUpdate) withObject:nil afterDelay:2.0];
}
else {
if ([delegate respondsToSelector:#selector(locationError:)]) {
[self.delegate locationError:#"Please Turn On Location Services in Settings To Retrive User's Current Location"];
}
else {
[Common showAlertWithTitle:#"Error" andMessage:#"Please Turn On Location Services in Settings To Retrive User's Current Location"];
}
}
}
-(void)startLocationUpdate
{
[self.locationManager startMonitoringSignificantLocationChanges];
}
#pragma mark CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if ([delegate respondsToSelector:#selector(locationUpdate:)]) {
[delegate locationUpdate:newLocation];
}
}
-(void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
if ([delegate respondsToSelector:#selector(locationError:)]) {
[delegate locationError:#"Some Error Occured While Retriving Users's Location"];
}
else {
[Common showAlertWithTitle:#"Error" andMessage:#"Some Error Occured While Retriving Users's Location"];
}
}
#end
But it is not returning any location update.
Also its not asking user permission to use location. My app is not listed in Location Services. How can I add my app in Location Serverices ?
What's worong in above code ?
I solved this problem by declaring UserLocation *userLocation in .h & writing property.
Since I am using ARC , its deallocating userLocation so I am not getting location updates.
I am following a tutorial to integrate GPS to my application. I want to display the Latitude and Longitude values in the viewDidLoad method. According to the tutorial they have displayed it from another method. But i need it to be displayed in viewDidLoad. How can i modify the following code to display it in viewDidLoad ?
The HelloThereController.h view controller
#import "MyCLController.h"
#interface HelloThereViewController : UIViewController <MyCLControllerDelegate> {
MyCLController *locationController;
}
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
The HelloThereController.m view controller
#import "HelloThereViewController.h"
#implementation HelloThereViewController
- (void)viewDidLoad {
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
//I need to print the latitude and logitude values here..
}
My MyCLController.h class
#protocol MyCLControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyCLController : NSObject {
CLLocationManager *locationManager;
id delegate;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, assign) id delegate;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
#end
My MyCLController.m class
#import "MyCLController.h"
#implementation MyCLController
#synthesize locationManager;
#synthesize delegate;
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[self.delegate locationUpdate:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
}
- (void)dealloc {
[self.locationManager release];
[super dealloc];
}
#end
If this view controller loads as soon as the app loads, you can't.
it takes time for the location manager to get gps updates.
you'll need to display some ui component that lets the user know you're getting the location, such as UIActivityIndicatorView, and setup another method for displaying the coordinates when you get them.
In general you can accelerate the process sacrificing some accuracy setting the desiredAccuracy property. According to the documentation the values are:
kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyKilometer
kCLLocationAccuracyThreeKilometers
Anyway you are interested in the first location, so still according to the documentation:
When requesting high-accuracy location data, the initial event delivered by the location
service may not have the accuracy you requested. The location service delivers the initial
event as quickly as possible. It then continues to determine the location with the accuracy
you requested and delivers additional events, as necessary, when that data is available.
You can try starting the location manager in the AppDelegate didFinishLaunchingWithOptions to have some more time before the view appears. As said by Frederick Cheung, locationManager.location can be nil, so it's better do the operations in the location manager delegate.
I am using CLLocationManager *locationManager and getting coordinates but these coordinates are not exact as google map coordinates.
iPhone coordinates are the following
<+26.86126232,+75.75962328>+/-100.00m(speed -1.00 mps/course-1.00)
google map coordinates for same device's location place coordinates are following
<+26.860524,+75.761569>
Google map coordinates are right but iPhone coordinates are wrong these are 100 meter away from google map's exact coordinates.
How do I get the exact coordinates.
// MyCLController.h
// mapCurrentLocation
//
// Created by mac on 18/11/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#protocol MyCLControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyCLController : NSObject<CLLocationManagerDelegate> {
IBOutlet UILabel *locationLabel;
CLLocationManager *locationManager;
id delegate;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, assign) id delegate;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
#end
//
// MyCLController.m
// mapCurrentLocation
//
// Created by mac on 18/11/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "MyCLController.h"
#implementation MyCLController
#synthesize locationManager;
#synthesize delegate;
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // send loc updates to myself
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// NSLog(#"Location: %#", [newLocation description]);
[self.delegate locationUpdate:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
//NSLog(#"Error: %#", [error description]);
[self.delegate locationError:error];
}
- (void)dealloc {
[self.locationManager release];
[super dealloc];
}
#end
and here i am using this class--
#import "mapCurrentLocationViewController.h"
#implementation mapCurrentLocationViewController
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
*/
- (void)viewDidLoad {
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location {
locationLabel.text = [location description];
}
- (void)locationError:(NSError *)error {
locationLabel.text = [error description];
}
- (void)dealloc {
[locationController release];
[super dealloc];
}
#end
To get the most accurate possible location measurements, set locationManager.desiredAccuracy = kCLLocationAccuracyBest; before you startUpdatingLocation.
Also, check the timestamp and horizontalAccuracy of the CLLocation objects that get delivered to locationManager:didUpdateToLocation:fromLocation:. If the location measurement seems like it's older or less accurate than you'd like, set a timer and wait for some more location measurements to be delivered. Core Location will often deliver a cached and/or imprecise location quickly, and then follow up with refined location measurements that are more accurate.
I tried to make a goelocation to my iPhone app exactly as shown in this tutorials : http://www.youtube.com/watch?v=qNMNRAbIDoU
my problem is when I build and go i see the map but the geolocation service didn't track my position, so I see just the global map :(
Here is my code I hope you can help me to identifiy the problem :
appdelegate.h
#interface WhereAmIAppDelegate : NSObject <UIApplicationDelegate,CLLocationManagerDelegate> {
UIWindow *window;
WhereAmIViewController *viewController;
CLLocationManager *locationManager;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) IBOutlet WhereAmIViewController *viewController;
appdelegate.m:
#implementation WhereAmIAppDelegate
#synthesize window;
#synthesize viewController;
#synthesize locationManager;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.locationManager=[[[CLLocationManager alloc] init] autorelease];
if([CLLocationManager locationServicesEnabled]) {
self.locationManager.delegate=self;
self.locationManager.distanceFilter=100;
[self.locationManager startUpdatingLocation];
}
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#pragma mark CLLocationManagerDelegate Methods
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
MKCoordinateSpan span;
span.latitudeDelta=0.2;
span.longitudeDelta=0.2;
MKCoordinateRegion region;
region.span=span;
region.center=newLocation.coordinate;
[viewController.mapView setRegion:region animated:YES];
viewController.mapView.showsUserLocation=YES;
viewController.latitude.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
viewController.longitude.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
}
#end
MyViewController.h
#interface WhereAmIViewController : UIViewController {
MKMapView *mapView;
UILabel *latitude;
UILabel *longitude;
}
#property (nonatomic,retain)IBOutlet MKMapView *mapView;
#property (nonatomic,retain)IBOutlet UILabel *latitude;
#property (nonatomic,retain)IBOutlet UILabel *longitude;
myViewController.m :
#implementation WhereAmIViewController
#synthesize mapView;
#synthesize latitude;
#synthesize longitude;
- (void)dealloc {
[mapView release];
[latitude release];
[longitude release];
[super dealloc];
}
#end
Two things to check:
1) The simulator does not have location, it will always show the lat/long of the Apple headquarters in California
2) It takes a little bit of time for the location to get settled, so if you ask for location right away you won't get one.
Also, you need some more code in your WhereAmI view controller. Usually you will see something in the viewWillAppear. Here is a link to a Big Nerd Ranch tutorial on view controllers and map views. Maybe it will help you.
There are a few things here to note:
1) The iPhone emulator does not have GPS capabilities, however it does have a default location of 1 Infinite Loop, Cupertino, CA (USA)
2) Your delegate method should be didUpdateFromLocation, not didUpdateToLocation.
I've been working to iron out memory leaks in my program and I'm down to a few stragglers. The strange thing is that they're coming from when I use CoreLocation to get a gps location. The code is properly returning the location, but it's leaking all over the place: CFHTTPMessage, CFURLConnection, CFURLRequest, CFURLResponse, GeneralBlock-16,-32,-48, HTTPRequest, etc... Could anyone please guide me how to fix this?
Initialization of MyCLController
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
Do some things and get a call back through the delegate:
[locationController release];
MyCLController.h:
#import <Foundation/Foundation.h>
#protocol MyCLControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyCLController : NSObject {
CLLocationManager *locationManager;
id delegate;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, assign) id delegate;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
#end
MyCLController.m:
#import "MyCLController.h"
#implementation MyCLController
#synthesize locationManager;
#synthesize delegate;
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // send loc updates to myself
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
[locationManager stopUpdatingLocation];
[self.delegate locationUpdate:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
[self.delegate locationError:error];
}
- (void)dealloc {
[super dealloc];
}
#end
You need to release the LocationManager. Make sure that you set its delegate to NULL prior to releasing. And also, it's not a good idea to just return the first result. Make sure horizontal accuracy is not < 0 and is also below some threshold, like 5000 meters. And to make it more robust, you might want to add a timer to make it stop after a given amount of time, if it couldn't find your location accurately enough.
you never release locationController