I have the following code in my ViewController:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
int desiredHA = 200;
RemoteDataController *rdc = [[RemoteDataController alloc]init];
double ha = newLocation.horizontalAccuracy;
if (ha <= desiredHA)
{
[rdc addLoc];
[self.locationManager stopUpdatingLocation];
return;
}
}
-(void)startLogging
{
if(self.locationManager==nil)
{
self.locationManager=[[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy=kCLLocationAccuracyBest;
self.locationManager.distanceFilter=kCLDistanceFilterNone;
}
if([CLLocationManager locationServicesEnabled])
{
NSLog(#"Start Location Tracking");
[self.locationManager startUpdatingLocation];
}
}
-(void)addLocResponse
{
NSLog(#"send checkin response");
self.silenceTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self
selector:#selector(onTick:) userInfo:nil repeats:NO];
}
-(void)onTick:(NSTimer *)timer
{
[self startLogging];
}
Then my RemoteDataController.m file looks like this:
#implementation RemoteDataController
-(void)addLoc
{
ViewController *vc = [[ViewController alloc]init];
[vc addLocResponse];
NSLog(#"Add Loc");
}
#end
I know this looks stupid right now but I stripped out a lot of the details of it so it's not too complicated.
My question is when I call addLocResponse from the RemoteDataController class the timer runs and then hits the onTick which fires of startLogging again. I can see it's running startLogging again from the NSLog but it does not run the locationManager delegate again.
If I keep all this in the ViewController it works fine but when I try to go out to RemoteDataController and back it does not work.
I am just trying to figure out what I am doing wrong here.
This is iOS6.
Any help would be great.
Thanks in advance!
You are not using a correct initializer for your view controller. Also, put a breakpoint on the dealloc method of your ViewController instance. Chances are it's being deallocated (if you are using ARC) because you are not doing anything with it (modal presentation or push).
Related
I'm trying to put everything location related inside a model. When I call this my MainViewController, the simulator doesn't ask me for my location, and nothing happens.
When I use the same code from my model, but put it directly in ViewDidLoad in my ViewController, everything works. I'm having a hard time understanding why.
Here is my model:
#implementation Location
{
CLLocationManager *_locationManager;
CLLocation *_location;
}
- (void)startLocationManager
{
NSLog(#"In startLocationManager");
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
_locationManager.delegate = self;
[_locationManager startUpdatingLocation];
}
#pragma mark - LocationManager Delegates
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"In didUpdateLocations");
if (locations) {
_location = [locations lastObject];
NSLog(#"%#", _location);
}
}
#end
I call this in my MainViewController like this:
- (void)viewDidLoad
{
[super viewDidLoad];
Location *location = [[Location alloc] init];
[location startLocationManager];
}
Why does the code work like a charm directly in the viewController, but not through my model?
I figured it out.
I needed to make location a property of your view controller instead of a local variable in the viewDidLoad. Otherwise it is created and deallocated within that method. I need it to live through the lifecycle of my view controller.
I'm trying to make an iOS7 app that uses the current location of the device. I'm using the iPhone simulator on my Mac, but I'm having some problems. Every time my view that the location manager is in appears, it prints out 0.000000 for both latitude and longitude, even after I've set a custom location (from simulator>debug>location).
Also, it seemed strange that the simulator didn't ask for permission to use current location when it opened the app. Anybody know what's going on here?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
_location = [locationManager location];
_coord.longitude = _location.coordinate.longitude;
_coord.latitude = _location.coordinate.latitude;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
_coord.longitude = _location.coordinate.longitude;
_coord.latitude = _location.coordinate.latitude;
printf("%f\n",self.coord.longitude);
printf("%f\n",self.coord.latitude);
}
You need to get the newLocation from the delegate method didUpdateLocationToLocation:fromLocation:. Also implement didFailWithError delegate method. It takes some time before you start getting updated locations, hence the delegate call.
The last location is usually cached, so it maybe wise to check location's timestamp and filter the old location out.
Edit:
This is the cleanest example I can provide. Start new project in Xcode, pick Single View application template, iPhone. Don't touch storyboard, just replace content of your ViewController.m with this and run in Simulator or device. If on Simulator, go to Debug and set some location and you will get coordinates in the console. I am also starting and stopping location updates when the view goes on or off screen.
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#implementation ViewController
#pragma mark - Location Manager delegate methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([newLocation.timestamp timeIntervalSinceNow] >= -300.0) {
NSLog(#"updated location with latitude %f longitude %f", newLocation.coordinate.longitude, newLocation.coordinate.latitude);
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.locationManager startUpdatingLocation];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.locationManager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if(error.code == kCLErrorDenied) {
// alert user
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Access to location services is disabled"
message:#"You can turn Location Services on in Settings -> Privacy -> Location Services"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if(error.code == kCLErrorLocationUnknown) {
NSLog(#"Error: location unknown");
} else {
NSLog(#"Error retrieving location");
}
}
#pragma mark - Location Manager getter
- (CLLocationManager *)locationManager
{
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
_locationManager.distanceFilter = 60.0;
}
return _locationManager;
}
#end
I am using CLLocationManager class. I have a simple class method for capturing the location
+(void)captureLocation{
mLocationManager = [[CLLocationManager alloc]init];
mLocationManager.delegate = (id<CLLocationManagerDelegate>)self;
mLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
[mLocationManager startUpdatingLocation];
}
and i have the delegate methods of CLLocationManager also
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
}
now i am trying to call this method in my viewDidLoad as
- (void)viewDidLoad
{
[super viewDidLoad];
[myclass captureLocation];
}
the method is getting called but the delegate methods are not getting called.
I have other class method also and from there if I try to call the method again the captureLocation method is getting called but the delegate methods are not called. Here is the other class method
+(void)initialize{
[self captureLocation];
}
please help me to find out why delegate methods are not getting called as I am new to this field. Thanks in advance.
Also know that CoreLocation permissions have changed with iOS 8. If you don't request the new permissions authorizations, CoreLocation doesn't do anything. It fails quietly because the delegate methods are never called.
I realize this question was asked in 2013, but if you are having a similar problem with the delegate methods not getting called, this article is extremely helpful:
http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/
While the article is very detailed and long, the actual code fix can be as minor as this:
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
And you have to add a value to info.plist, which is the message to display in the permissions alert. See screen grab.
Key: NSLocationWhenInUseUsageDescription
Value: Location is required to find out where you are (You can change that to whatever you want)
You are setting the delegate of the CLLocationManager inside a class method (i.e. one prefixed by + rather than -). So, when you reference self within that class method, that's the class, not an instance of the class. So, you are trying to set the delegate to the class rather than an instance of the class.
That won't work. The delegate methods are instance methods, not class methods. (This is presumably why you had to use the CLLocationManagerDelegate cast when assigning the delegate.)
You must actually instantiate whichever class you've implemented the CLLocationManagerDelegate methods. If you don't want to tie that instance to a particular view controller, you could use a singleton pattern. Regardless, you can set the location manager's delegate to point to that instance of that class.
For example, if you wanted it to be a singleton:
// MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
+ (instancetype)sharedManager;
- (void)startCapture;
- (void)stopCapture;
#end
and
// MyClass.m
#import "MyClass.h"
#import <CoreLocation/CoreLocation.h>
#interface MyClass () <CLLocationManagerDelegate>
#property (nonatomic, strong) CLLocationManager *locationManager;
#end
#implementation MyClass
+ (instancetype)sharedManager
{
static id sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (void)startCapture
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
}
- (void)stopCapture
{
[self.locationManager stopUpdatingLocation];
self.locationManager = nil;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
// ...
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// ...
}
#end
And then,
- (void)viewDidLoad
{
[super viewDidLoad];
[[MyClass sharedInstance] startCapture];
}
Calling self in a + method set your delegate to nil as it means ClassName as in [[ClassName alloc] init].
you need to:
mLocationManager.delegate = mLocationManager
instead of
mLocationManager.delegate (id<CLLocationManagerDelegate>)self;
in ios6 locationManager:didUpdateToLocation:fromLocation: is deprecated so you need to add another method in your code ...
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// this method get called in ios7 .
}
In iOS -8 need to do some changes :
Please have a look into this :Get current location in iOS-7 and iOS-8
I am making a simple map app - I am sending and receiving locations and text on a pubnub channel. When a chat message comes in, I want to use a simple MKAnnotation to draw the chat (I'm aware this is a horrifying act of UX and I don't care).
When my app delegate receives a message on the pubnub channel, it calls a method in the main view controller to draw the text message on the map. The method should use the latest user location for the pin's coordinates.
I'm not sure why, but I can't get the annotation to show from within my method. I have tried building the annotation from within the method and showing it. I've also tried making a custom annotation class and calling it from within my method. When I use the very same annotation code but hardcode it in my viewDidLoad then it shows up just fine. Any insight would be most appreciated.
My App Delegate:
#import "MyLocationAppDelegate.h"
#import "MyLocationViewController.h"
#implementation MyLocationAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[PubNub setDelegate: self];
return YES;
}
- (void)pubnubClient:(PubNub *)client didReceiveMessage:(PNMessage *)message
{
NSString* text = message.message;
//Call drawChat method of MyLocationViewController
MyLocationViewController *MyLocViewController = [[MyLocationViewController alloc] init];
[MyLocViewController drawChat:text];
}
My View Controller:
#import "MyLocationViewController.h"
#import "MyLocationAppDelegate.h"
#import "MyLocationAnnotation.h"
CLLocation *userLocation;
#implementation MyLocationViewController {
CLLocationManager *locationManager;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Delegate map view
self.mapView.delegate = self;
[self SetUpChat];
[self configurePubNub];
//Instantiate location manager
if (nil == locationManager) {
locationManager = [[CLLocationManager alloc] init];
}
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
NSLog(#"Application: viewDidLoad");
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
userLocation = [locations lastObject];
}
- (void)drawChat:(NSString *)message
{
//Create new annotation object
CLLocationCoordinate2D location;
location.latitude = userLocation.coordinate.latitude;
location.longitude = userLocation.coordinate.longitude;
MyLocationAnnotation *chat = [[MyLocationAnnotation alloc] initWithLocation:location andTitle:message];
[self.mapView addAnnotation:chat];
}
And MyLocationAnnotation.m
#import "MyLocationAnnotation.h"
#implementation MyLocationAnnotation
- (id)initWithLocation:(CLLocationCoordinate2D)coord andTitle:(NSString *)ttl {
self = [super init];
if (self) {
_coordinate = coord;
_title = ttl;
}
return self;
}
#end
Thanks to Anna's pointing out what I was doing wrong I was able to fix this:
Instead of redclaring my main view controller in the app delegate I did this instead:
MyLocationViewController *mainController = (MyLocationViewController *) self.window.rootViewController;
[mainController drawChat:text];
I was then able to call the method just fine with the data from app delegate.
I'm making an app that determines a user's location and makes the [locationManager startUpdatingLocation] call in the initWithNibName function, but initWithNibName isn't being called right off the back so I added a call for it in the AppDelegate.m:
WhereamiViewController *wvc = [[WhereamiViewController alloc] initWithNibName:#"WhereamiViewController" bundle:nil];
This works, however then there is a problem with calling this function within the initWithNibName function: [locationManager startUpdatingLocation]. It literally returns nothing. But, if I change my code to call initWithNibName in my viewDidLoad line, it works. Why is this? I'm very confused and have been searching for answers but I'm at a standstill. I understand initWithNibName needs to be called, but I don't understand why it won't work if I call it from AppDelegate.m.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations`
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
Here is my initWithNibName function:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
// Set a movement threshold for new events.
locationManager.distanceFilter = 500; // meters
[locationManager startUpdatingLocation];
}
return self;
}
you do have a Xib file set up right?
things to try:
if you are not using Nibs then create a method called init:
- (id) init {
self = [super init];
if(self) {
//call code here
}
return self;
}
and then instead of calling nib method in app delegate just call init
or second option would be to call the code straight in viewdidload instead of doing above