Singleton LocationManager starting updates? - iphone

Why is this CLLocationManager inside my singleton not working? I took this code http://jinru.wordpress.com/2010/08/15/singletons-in-objective-c-an-example-of-cllocationmanager/
Not altertering his code at all (so if I should add something to his code let me know) its my first singleton ever.
- (CLLocationManager *)locationManager {
if (locationManager != nil) {
return [LocationController sharedInstance].locationManager;
}
self.locationManager = [LocationController sharedInstance];
[LocationController sharedInstance].locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
return [LocationController sharedInstance].locationManager;
}
(void)viewDidLoad
{
[super viewDidLoad];
// Start the location manager.
[LocationController sharedInstance].delegate = self;
//[[self locationManager] startUpdatingLocation];
[[LocationController sharedInstance].locationManager startUpdatingLocation];

I don't quite understand what you want to achieve in your - (CLLocationManager *)locationManager method here. But in the init function in LocationController.h, you should add something like this:
- (id)init
{
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
return self;
}
And when you want to call the singleton object in other controller to update the location, you should be able to just call:
[[LocationController sharedInstance].locationManager startUpdatingLocation];
Remember to also implement the delegate method - (void)locationUpdate:(CLLocation*)location in your controller.
Hope it helps this time if my post didn't.

Perhaps the problem is in the delegate. This points to the file, not the singleton.

Assuming that - (CLLocationManager *)locationManager is a method of LocationController the line
self.locationManager = [LocationController sharedInstance];
makes no sense as you assign the singleton instance of LocationController to self.locationManager which is of type CLLocationManager.

Here is what I did and you can find the complete example on github.
https://github.com/irfanlone/CLLocationManager-Singleton-Swift

Related

How to stop CLLocation manager updating IMMEDIATELY

I am having ClLocationManager code in my viewWillAppear. I the same view controller I am having a button which opens a web view. I want to stop location manager IMMEDIATELY, when user taps on button. I am using [locationManager stopUpdating] and locationManager.delegate = nil. From CLLOCATION delegate method I open MFMailComposer sheet.
Problem: Even after clicking on button (which is opening web view), my MailComposerCode executes. How to stop it?
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
[self setUpProgressBar];
if (webViewButtonClicked == YES)//when user came bck from web view pick up latest coordinates
{
webViewButtonClicked = NO;
[self getLocationCoordinates];
}
else//get latest coordinates from CLLocation manger
{
if (!locationManager) {
locationManager = [[CLLocationManager alloc] init];
}
if (!self.geocoder) {
self.geocoder = [[CLGeocoder alloc] init];
}
locationManager.delegate = self;
// This is the most important property to set for the manager. It ultimately determines how the manager will
// attempt to acquire location and thus, the amount of power that will be consumed.
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// When "tracking" the user, the distance filter can be used to control the frequency with which location measurements
// are delivered by the manager. If the change in distance is less than the filter, a location will not be delivered.
locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters;
// Once configured, the location manager must be "started".
[locationManager startUpdatingLocation];
}
}
- (IBAction)goToWEBVIEW
{
NSLog(#"setting to YES");
webViewButtonClicked = YES;
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
aWebViewController = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:nil];
[self.navigationController aWebViewController animated:NO];
}
CLLocationManager delegate method:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
if (webViewButtonClicked==NO)
{
NSLog(#"1234");
if (!self.sender) {
[self.gpsActivityindicator stopAnimating];
[self stopUpdatingLocation:#""];
self.destinationForProgressView = .25;
[NSThread detachNewThreadSelector:#selector(startTheBackgroundJob) toTarget:self withObject:nil];
**[self openMailComposer];**
}
}
}
So you can see in goToWebView method I am having a flag webViewButtonClicked = YES, but delegate method is called before the user has tapped on web view button. So condition if (webViewButtonClicked==NO) becomes true? How can I stop this scenario?
Thanks.
- (IBAction)goToWEBVIEW
{
[locationManager stopUpdatingLocation];
NSLog(#"setting to YES");
webViewButtonClicked = YES;
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
aWebViewController = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:nil];
[self.navigationController aWebViewController animated:NO];}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[locationManager stopUpdatingLocation];
if (webViewButtonClicked==NO)
{
NSLog(#"1234");
if (!self.sender) {
[self.gpsActivityindicator stopAnimating];
[self stopUpdatingLocation:#""];
self.destinationForProgressView = .25;
[NSThread detachNewThreadSelector:#selector(startTheBackgroundJob) toTarget:self withObject:nil];
**[self openMailComposer];**
}
}
}

mapViewDidLoad method not loaded

New to objective c, and I am using ArcGIS for the map portion. I have a problem where the method mapViewDidLoad is not called/loaded. Here is some part of the code:
.h file
#interface ViewController : UIViewController<AGSMapViewLayerDelegate, AGSMapViewTouchDelegate, AGSMapViewCalloutDelegate>{
AGSMapView *_mapView;
AppDelegate *appDelegate;
...
}
.m file
- (void)viewDidLoad
{
[super viewDidLoad];
[self.activityView startAnimating];
self.mapView.touchDelegate = self;
self.mapView.calloutDelegate = self;
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
...
}
- (void)mapViewDidLoad:(AGSMapView *)mapView {
AGSEnvelope *envelope = [[AGSEnvelope alloc]initWithXmin:29757.610204117
ymin:40055.0379682464
xmax:29884.6992302249
ymax:40236.6028660071
spatialReference:self.mapView.spatialReference];
[self.mapView zoomToEnvelope:envelope animated:YES];
self.mapView.callout.width = 195.0f;
self.mapView.callout.accessoryButtonHidden = YES;
[self.mapView.gps start];
[self.mapView centerAtPoint:self.mapView.gps.currentPoint animated:YES];
NSLog(#"Location : %#", self.mapView.gps.currentPoint);
[self.activityView stopAnimating];
self.activityView.hidden = YES;
}
What is wrong with my code why i doesn't load the mapViewDidLoad method.
Thanks in advance.
make sure that mapviewdelegate is connected by right click on mapview and then assign delegate..
or add [self.mapview setDelegate:self];
in your case "AGSMapView" mapViewDidLoad: method on AGSMapViewLayerDelegate is invoked after the first layer has been added to the map. At this point, the component is fully functional you can find reference to it in
http://help.arcgis.com/en/arcgismobile/10.0/apis/iphone/reference/interface_a_g_s_map_view.html
make self.mapview.layerDelegate = self;
Just add self.mapView.delegate = self; in viewDidLoad

Can't allocate CLLocationManager

In my UIViewController's initWithNibNameOrNil, I call:
locationManager = [CLLocationManager new];
to create the object, then later in viewDidAppear I call:
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
But I never receive a location update; the location manager never starts updating the location. Yet if I replace that same line the initWithNibNameOrNil with:
locationManager = [[myAppDelegate appDelegate] locationManager];
everything works great, except for random crashes sometimes when
locationManager.delegate = self;
is set in the very next line after location manager is set to the already allocated manager in the app delegate. None of this makes sense to me; I don't understand why one is different from the other, much less why neither of them works consistently. Can someone please enlighten me?
Summary:
Method 1 (does not work):
In MapView.m:
initWithNibNameOrNil:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self) {
locationManager = [CLLocationManager new];
locationManager.delegate = self;
locationManager.distanceFilter = kCLHeadingFilterNone;
locationManager.headingFilter = 3;
if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull))
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
else
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//more setup irrelevant to the question
}
return self;
}
viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
}
Notes: Using this method of creating the location manager, location services never get enabled after startUpdatingLocation is called in viewDidAppear and so no location updates are ever received.
Method 2 (does work, mostly):
In myAppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
self.locationManager = [CLLocationManager new];
self.locationManager.distanceFilter = kCLHeadingFilterNone;
self.locationManager.headingFilter = 3;
if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull))
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
else
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//more irrelevant setup
}
In MapView.m:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if(self) {
locationManager = [[Trail_TrackerAppDelegate appDelegate] locationManager];
locationManager.delegate = self;
//more irrelevant setup
}
return self;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
}
Notes: this allocation method works, except if I push MapView, then pop it, push it again, pop it again, then try to push it again, I get a crash every time at the line in initWithNib... where I set the delegate to self; NSZombieEnabled says:
-[CLLocationManager setDelegate:]: message sent to deallocated instance 0x9540ad0
Interesting...
NSLog(#"%s: %#; %#", PRETTY_FUNCTION, self, locationManager) says this:
-[MapView initWithNibName:bundle:]: <MapView: 0x92ae3e0>; <CLLocationManager: 0x92a3560>
Method 3 (works all-around):
In MapView.m:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
locationManager = [CLLocationManager new];
locationManager.delegate = self;
locationManager.distanceFilter = kCLHeadingFilterNone;
locationManager.headingFilter = 3;
if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull))
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
else
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
}
Notes: all of the allocation and setup is done in viewDidAppear, and I don't get any crashes after repeated pushing/popping of the view controller. This is great, but I don't like allocating in viewDidAppear because the app lags for just a moment because (I think) the allocation of locationManager clogs up the main thread for that time. I just really don't understand why Method 1 doesn't work at all, Method 2 crashes, and Method 3 works. Don't they all do more-or-less the same thing?
Sorry for all the code, and congrats to anyone who made it all the way through this maze of a question! :)
Try:
locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
instead of new. Are you sure you are assigning the delegate as self? Otherwise your class won't listen for location updates.
Turns out the culprit was a seemingly-innocent piece of code that was turning off the location manager as soon as it was being started. The only reason I saw it was because I compared the project to a recent backup, and noticed the difference. Another problem solved because of backing up!
Careful where you're defining your location manager.
When using ARC, it could happen that your location manager instance gets discarded.

Getting Longitude and Latitude Values

I am trying to connect to GPS from my code. I am doing so according to this tutorial.
- (void)viewDidLoad {
[super viewDidLoad];
CLController = [[CoreLocationController alloc] init];
CLController.delegate = self;
[CLController.locMgr startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location {
locLabel.text = [location description];
}
- (void)locationError:(NSError *)error {
locLabel.text = [error description];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
The above code is placed in a view controller called GetMyLocationViewController, and I have another view controller called MainScreenViewController.
When the screen loads, the MainScreenViewController gets loaded, and I will need the GPS location to continue operations with this screen.
In the ViewDidLoad method of MainScreenViewController I wrote the following;
- (void)viewDidLoad {
[super viewDidLoad];
GetMyLocationViewController *getMyLocationViewController = [[GetMyLocationViewController alloc]initwithXib:nil bundle:nil];
[self.navigationController pushViewController:getMyLocationViewController Animation:YES];
// AND THEN I NEED TO ACCESS THE LONGITUDE AND LATITUDE VALUES
}
When the above code gets executed, the viewDidLoad method of MainScreenViewController gets executed, but not the locationUpdate method. The only way I could get the values of longitude and latitude is by the execution of locationUpdate method. So how can I get these values?
Do you tested in a device? xcode before the version 4.2 dont have a GPS simulator, because of that the method locationUpdate never call.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([self.delegate conformsToProtocol:#protocol(CoreLocationControllerDelegate)]) { // Check if the class assigning itself as the delegate conforms to our protocol. If not, the message will go nowhere. Not good.
[self.delegate locationUpdate:newLocation];
}
}
Are you sure you are loading your GetMyLocationViewController? Your code only shows loading the MainScreenViewController, which, in its -viewDidLoad method, loads itself again, which would cause an infinite loop of loading and pushing MainScreenViewControllers.
UPDATE: That CoreLocationController class in the tutorial seems unnecessary. Rather that using it, make CLLocationManager a property of your GetMyLocationViewController. Make GetMyLocationViewController's -viewDidLoad method look like this:
-(void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
}
don't forget to import the CoreLocation library and implement the delegate methods.

stop location updates from the iphone UI?

Is it possible to start / stop location updates from the UI of the iphone? All I need from the app is to show me my location unless I click "stop" and then "start" again.
I can't seem to be able to do that...I have my location displayed properly, and I also created two IBButtons and created a function for each of them, however, my app crashes when I click on each one of those buttons. I placed those functions under the viewcontroller.m.
I am kind of new to this, so any help would be appreciated. Thanks!
(IBAction)startUpdating: (CLLocation *)location
{
[location startUpdatingLocation];
}
(IBAction)stopUpdating: (CLLocation *)location
{
[location stopUpdatingLocation];
}
start/stopUpdatingLocation are CLLocationManager instance methods, rather than CLLocation instance methods... so create a CLLocationManager instance.
.h
#interface someClass:somesuperclass{
CLLocationManager * locationManager;
BOOL updating;
}
-(IBAction)toggleUpdating:(id)sender;
#end
.m somewhere in the view load/ or init cycle:
-(void)viewDidLoad{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
}
-(void)viewDidUnload{
[locationManager stopUpdatingLocation];
[locationManager release];
[super viewDidUnload];
}
-(IBAction)toggleUpdating:(id)sender
{
if(!updating)
{
[locationManager startUpdatingLocation];
}else{
[locationManager stopUpdatingLocation];
}
updating = !updating;
}
also your action above will never work, because the thing after a colon in an action will be the object that sent the action, a UIButton in your case.