Disappearing UILocation alerts in XCode 4.2 with ARC iPhone - iphone

The alerts appear for a split-second or did not show when application launches in project with ARC (without using ARC all it's OK). (I add CoreLocation framework and I import it to project).
My code:
#import <CoreLocation/CoreLocation.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
CLLocationCoordinate2D coordinate;
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
NSLog(#"jestem po okienku ");
if (locationManager.locationServicesEnabled == NO)
{
coordinate.latitude = 0.0;
coordinate.longitude = 0.0;
}
else
{
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
CLLocation *location = [locationManager location];
if (!location) {
coordinate.latitude = 0.0;
coordinate.longitude = 0.0;
}
// Configure the new event with information from the location.
coordinate = [location coordinate];
}
return YES; }

You are storing the location manager pointer in a local variable. So ARC is free to release that location manager before returning from this method.
If you wish to keep that location manager alive for longer you need to keep a longer term strong reference to it. Like an ivar or property.

Related

"StopUpdatingLocation" is called but GPS Arrow doesnt disappear

I don´t understand why the gray gps arrow don´t disappear after stopUpdatingLocation is called. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if (self.locationManager == nil)
{
self.locationManager = [[[CLLocationManager alloc] init]autorelease];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
}
CLLocation *location = [self.locationManager location];
CLLocationCoordinate2D coordinate = [location coordinate];
g_lat = coordinate.latitude;
g_lng = coordinate.longitude;
[self.locationManager startUpdatingLocation];
}
And here ist my didUpdateLocation:
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Core location has a position.");
CLLocationCoordinate2D coordinate = [newLocation coordinate];
global_lat = coordinate.latitude;
global_lng = coordinate.longitude;
[self.locationManager stopUpdatingLocation];
}
- (void) locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Core location can't get a fix.");
}
I also checked if any other app is using GPS!
After 20 minutes the Arrow is still there....
Thanks for help!
EDIT:
I think i missed something very important, on my first view after the App is started there is a Google Map! This is my Code:
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:g_lat
longitude:g_lng
zoom:15];
self.mapView = [GMSMapView mapWithFrame:CGRectMake(1.0f, 160.0f, 320.0f, 100)
camera:camera];
self.mapView.delegate = self;
self.showsUserLocation = YES;
self.mapView.trafficEnabled = YES;
self.mapView.myLocationEnabled = YES;
self.mapView.settings.myLocationButton = YES;
self.mapView.settings.compassButton = YES;
[self.mapView setUserInteractionEnabled:YES];
[self.mapView setCamera:camera];
[self.containerView addSubview:self.mapView];
Is it possible that the google map is updating all the time? If Yes, how can i stop that?
Regarding the google map: do you turn off the myLocationEnabled field when you push the new view controller? If not, then that can keep the GPS running. You can try it by not starting the GPS on the next view controller. If the GPS stays on, then the map is holding it.
Side note: This can be part of the normal operation. If your app stops receiving the location updates, then you are doing fine. iOS is doing lots of optimizations and leaving the GPS on for some time is probably part of this. During testing I saw that the arrow usually stays on for a while even if the app is killed from XCode.

iOS set ViewController and AppDelegate as listeners to CoreLocation model class

How do you set up the AppDelegate and a ViewController to be listeners to a model corelocation class? What are the proper design choices??
I'm interested in having a model class to implement CoreLocation and location updates. I'm guessing this class should be a sharedSingleton, because both my AppDelegate and ViewController wish to access it.
When my viewController calls it, I want the CLLocationManager to use startUpdatingLocation.
When the app goes into background, I want to monitor location updates in the AppDelegate using startMonitoringSignificantLocationChanges.
My question is, how do I set up the model class to handle these different types of location updates, as well as notify the ViewController or AppDelegate that a new location is found? Using NSNotification? Delegation doesn't seem to work because it's a one-to-one relationship.
Appreciate your help on figuring out how to design this.
Thanks!
You can have locationManager in the AppDelagete. And let the app delegate handle for you the location updates for all the application.
AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate,CLLocationManagerDelegate...> {
...
CLLocationManager* locationManager;
CLLocationCoordinate2D myLocation;
...
}
#property(nonatomic) CLLocationCoordinate2D myLocation;
...
#end
AppDelegate.m
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
...
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[locationManager startMonitoringSignificantLocationChanges];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
myLocation = newLocation.coordinate;
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateControlersThatNeedThisInfo" object:nil userInfo:nil];
}
...
In your controller:
ViewController.m
...
- (void)viewDidAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(yourFunction) name:#"updateControlersThatNeedThisInfo" object:nil];
}
-(void)yourFunction{
AppDelegate *app = [[UIApplication sharedApplication] delegate];
CLLocation myLocation = app.myLocation;
if(app.applicationState == UIApplicationStateBackground)
//background code
else
//foreground code
...
}

CLLocationManager delegates not working after initialization

I am trying to get the compass of the iphone to work using the rhomobile framework.
I already did the rhomobile part, created a working wrapper that calls native methods on the iphone, but I cant manage to get the events to work.
Locationmanager.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface locationController : NSObject <CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
}
#property (strong, nonatomic) CLLocationManager *locationManager;
- (id)init;
- (void)dealloc;
#end
Locationmanager.m
#import "Locationmanager.h"
#include "ruby/ext/rho/rhoruby.h"
//store the values
double gx, gy, gz, gth;
//init location
locationController *lc;
#implementation locationController
#synthesize locationManager;
- (id)init {
if (self = [super init]) {
self.locationManager = [[CLLocationManager alloc] init];
NSLog(#"%#", [CLLocationManager headingAvailable]? #"\n\nHeading available!\n" : #"\n\nNo heading..\n");
NSLog(#"%#", [CLLocationManager locationServicesEnabled]? #"\n\nLocation available!\n" : #"\n\nNo location..\n");
// check if the hardware has a compass
if ([CLLocationManager headingAvailable] == NO) {
// No compass is available. This application cannot function without a compass,
// so a dialog will be displayed and no magnetic data will be measured.
locationManager = nil;
UIAlertView *noCompassAlert = [[UIAlertView alloc] initWithTitle:#"No Compass!" message:#"This device does not have the ability to measure magnetic fields." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[noCompassAlert show];
[noCompassAlert release];
NSLog(#"\n***** ERROR *****\n No compass found !!!");
} else {
// setup delegate callbacks
locationManager.delegate = self;
// heading service configuration
locationManager.headingFilter = kCLHeadingFilterNone;
// location service configuration
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
//start location services
[locationManager startUpdatingLocation];
// start the compass
[locationManager startUpdatingHeading];
}
return self;
}
}
- (void)dealloc {
[super dealloc];
// Stop the compass
[locationManager stopUpdatingHeading];
[locationManager release];
}
// This delegate method is invoked when the location manager has heading data.
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading {
NSLog(#"\n\n***** New magnetic heading *****\n %f\n", heading.magneticHeading);
NSLog(#"\n\n***** New true heading *****\n %f\n", heading.trueHeading);
gx = heading.x;
gy = heading.y;
gz = heading.z;
gth = heading.trueHeading;
}
// This delegate method is invoked when the location managed encounters an error condition.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if ([error code] == kCLErrorDenied) {
// This error indicates that the user has denied the application's request to use location services.
NSLog(#"\n ***** ERROR *****\n Location not allowed!");
[locationManager stopUpdatingHeading];
} else if ([error code] == kCLErrorHeadingFailure) {
NSLog(#"\n ***** ERROR *****\n Magnetic interference or something!");
}
}
#end
//ruby wrappers
void locationmanager_init(void) {
// make sure we can only start this method once
static bool started = false;
if(!started) {
// Initialize the Objective C accelerometer class.
lc = [[locationController alloc] init];
started = true;
}
}
void locationmanager_get_heading(double *x, double *y, double *z, double *th) {
NSLog(#"\n ***** DEBUGGER *****\n Getting heading x: %f, y: %f, z: %f, heading: %f", gx, gy, gz, gth);
*x = gx;
*y = gy;
*z = gz;
*th = gth;
}
I'm running the code on an iphone 4 with iOS 5.1, in the console I can see the debug messages of init, but I never see a debug message of the didUpdateHeading delegate. Anyone got a clue what I missed here?
UPDATE
I think I need to run my code in a background thread to get it working. Currently the locationmanager_init initializes + leaves the code, therefor its not active and the events are not fired.
Anyone got a simple solution initializing this in the background to keep it active?
UPDATE 2
Returned the id, used self = [super init] and still no fix :(
GitHub code
Initializes with locationmanager_init, retrieves data with locationmanager_get_heading
You have to init the CLLocationManager on the main thread, check this SO here, or run it from a thread with an active run loop, check this SO here, From Apple documentation:
Configuration of your location manager object must always occur on a thread with
an active run loop, such as your application’s main thread.
Make sure your locationController and the CCLocationManager inside it are alive past initialization, check here. I may be wrong here, but from your Github code, it seems that the *lc variable is getting released in the autorelease pool. Try giving it an extra retain.
lc = [[[locationController alloc] init] retain];
I guess this is the cause of your problem. If the object is released you wont get any updates.
Not related to the question but:
You should call [super dealloc] last but not first, check this SO here
Put the return statement in your init method before the last parenthesis, and not before the second last.
...
// start the compass
[locationManager startUpdatingHeading];
}
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateHeading:(CLHeading *)heading;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
These are your instance methods not delegate methods.
check
https://developer.apple.com/library/mac/#documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.html
Possibly this is not the solution to the overall problem, but your init method is missing a return statement:
- (id)init {
if (self = [super init]) {
// do your setup here
}
return self;
}

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.

CLLocationManager crashing on release, but why?

This might be one of those silly question where, once a solution is pointed out, makes you feel pretty stupid wondering how you didn't see it but I can't figure out why this part of my app is crashing with EXC_BAD_ACCESS (and no stack trace).
I have a CLLocationManager *locationManager (ivar declared in interface file) that gets created on viewDidLoad if locationServices is enabled:
- (void)viewDidLoad
{
[super viewDidLoad];
if ([CLLocationManager locationServicesEnabled])
[self findUserLocation];
...
}
#pragma mark - Location finder methods
- (void)findUserLocation
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[locationManager startUpdatingLocation];
}
So the location manager starts updating location and each time and update is found, the delegate method below is called, where I check to see if I should time out or continue looking for my desiredAccuracy:
#pragma mark - CLLocationManager delegates
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if ([newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp] > 8)
[self locationManagerTimeOut];
else if ((newLocation.horizontalAccuracy <= manager.desiredAccuracy) && (newLocation.verticalAccuracy <= manager.desiredAccuracy))
[self locationManagerLockedPosition];
}
If a position is locked, this method is called:
- (void)locationManagerLockedPosition
{
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
[locationManager release], locationManager = nil;
NSLog (#"add results to view");
}
If it times out, this is the method called:
- (void)locationManagerTimeOut
{
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
[locationManager release], locationManager = nil;
NSLog (#"Time out!");
}
Problem is, in either case (time out or locked position), I get the NSLog output in the console and then 2 secs later the app crashes??
Interesting thing is, if I comment out my [locationManager release]... line, everything works fine but WHY? Also if I move the [locationManager release] to my dealloc method, no crashes either!
Am I missing something basic here?
Thanks!
Rog
I had the same issue and there's probably some problem in the depths of CLLocationManager. Fixed by doing:
[locationManager stopUpdatingLocation];
[self performSelector:#selector(discardLocationManager) onThread:[NSThread currentThread] withObject:nil waitUntilDone:NO];
and in discardLocationManager do:
- (void) discardLocationManager
{
locationManager.delegate = nil;
[locationManager release];
}
You are release the CLLocationManager instance from within a callback method, which can't be a good idea.
The CLLocationManager calls your callbacks locationManager:didUpdateToLocation:fromLocation etc. If you release the location manager instance, you're basically deallocating the object that just called you. Bad idea. That's why the app crashes.
Instead of releasing the location manager instance, you could autorelease it.
Sargon