issue about iOS Core Location GPS - iphone

When initializing a new class, which methods of this class will be executed automatically.. Please take a look at codes below:
CoreLocationDemoViewController.m
- (void)viewDidLoad {
NSLog(#"CORE_LOCATION_DEMO_VIEW_CONTROLLER=======>VIEW_DID_LOAD");
[super viewDidLoad];
CLController = [[CoreLocationController alloc] init]; // line 1
CLController.delegate = self; // line 2
[CLController.locMgr startUpdatingLocation];
}
CoreLocationController.m
- (id)init {
NSLog(#"CORE_LOCATION_CONTROLLER=======>INIT");
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"CORE_LOCATION_CONTROLLER=======>DID_UPDATE_TO_LOCATION");
}
From debugging, I got
2011-10-11 23:44:31.682 CoreLocationDemo[77470:207] CORE_LOCATION_CONTROLLER=======>INIT
2011-10-11 23:44:31.707 CoreLocationDemo[77470:207] CORE_LOCATION_CONTROLLER=======>DID_UPDATE_TO_LOCATION
It seems that init and locationManager are executed automatically...I am not so sure about this...
Another question is at line 2, what
CLController.delegate = self ( delegate is declared as id delegate in CoreLocationController.h )
does
Please help if you were experiencing before and all comments are welcomed here

init() is called because of this
CLController = [[CoreLocationController alloc] init];
didUpdateToLocation is called because of this as a delegate call back
[CLController.locMgr startUpdatingLocation];
As a sidenote, I am noticing your init neither calls super init nor returns self. I guess you trimmed down that for the post.

Related

custom Location Manager class using CLLocationManager

I'm pretty new to iOS development (my first app) and I faced this issue.
I have an iPhone app that should get user's current location in multiple ViewControllers upon user button touch. To prevent redundant code (implementing locationManager:didFailWithError, locationManager:didUpdateToLocation:fromLocation, etc. multiple times in different view controllers) I decided to create a custom class called LocationManager:
LocationManager.h
#interface LocationManager : NSObject <CLLocationManagerDelegate> {
#private
CLLocationManager *CLLocationManagerInstance;
id<LocationManagerAssigneeProtocol> assignee;
}
-(void) getUserLocationWithDelegate:(id) delegate;
LocationManager.m
#implementation LocationManager
-(id)init {
self = [super init];
if(self) {
CLLocationManagerInstance = [[CLLocationManager alloc] init];
CLLocationManagerInstance.desiredAccuracy = kCLLocationAccuracyBest;
CLLocationManagerInstance.delegate = self;
}
return self;
}
-(void) getUserLocationWithDelegate:(id) delegate {
if([CLLocationManager locationServicesEnabled]) {
assignee = delegate;
[CLLocationManagerInstance startUpdatingLocation];
}
}
#pragma CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
...
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[CLLocationManagerInstance stopUpdatingLocation];
[assignee didUpdateToLocation:newLocation];
}
and I have a protocol called LocationManagerAssigneeProtocol that my ViewControllers implement
#protocol LocationManagerAssigneeProtocol <NSObject>
#required
-(void) didUpdateToLocation:(CLLocation *) location;
#end
and in my viewcontroller where needed
- (IBAction)getMyLocation:(id)sender {
[locationMgr getUserLocationWithDelegate:self];
}
This code works perfectly, however, I have a feeling that I'm violating some design patterns here by letting LocationManager be able to call a function of the class that itself initiated a call to Location Manager. On the other hand, I don't want to go with implementing CLLocationManagerDelegate for all my viewcontrollers that are supposed to work with locations.
Are there any better solution to this issue?
I agree with #CarlVeazey on this one. Delegate are great for a 1 to 1 relationship existing at any one time, however in your case it seems that you may need multiple viewControllers to respond to location events at any given time. So just remove anything related to your delegate and its associated protocol.
I'd probably make LocationManager class a singleton and modify the methods for updating:
+(LocationManager *)sharedInstance
{
static LocationManager *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
-(void)getUserLocation
{
if ([CLLocationManager locationServicesEnabled])
[CLLocationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[CLLocationManagerInstance stopUpdatingLocation];
[[NSNotificationCenter defaultCenter] postNotificationWithName:#"LocationManagerDidUpdateLocation" object:newLocation];
}
... Then any viewController that needs to use this class would have something like:
-(void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserverForName:#"LocationManagerDidUpdateLocation" object:self queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
CLLocation *location = note.object;
...
}];
}
-(IBAction)getMyLocation:(id)sender {
[[LocationManager sharedInstance] getUserLocation];
}
Hope that helps and makes sense.

CLLocationManager in background thread

I am doing one application.In that i am using the CLLocationManager Class for getting the updated location latitude and longitude details.But i need to use this CLLocationManager in sepaate thread .I written my code like below.
- (void)viewDidLoad
{
[NSThread detachNewThreadSelector:#selector(fetch) toTarget:self withObject:nil];
}
-(void)fetch
{
manager=[[CLLocationManager alloc]init];
manager.delegate=self;
manager.distanceFilter=kCLDistanceFilterNone;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%f",newLocation.coordinate.latitude);
lbl.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
}
.But this delegate method is not fired when i run this code.So please guide me how to get the location updates in separate thread.
The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread. ——from apple document
Could you please tried with this.
dispatch_async(newThread, ^(void) {
[self fetch];
});
hope you'll get solved problem.
in .h file
MainView *ctl;
NSMutableDictionary *dictSubPoses;
- (id)initWithCtl:(MainView*)_ctl;
in .m file
- (id)initWithCtl:(MainView*)_ctl
{
if(self = [super init])
{
ctl = _ctl; //[_ctl retain];
}
return self;
}
- (void)main
{
[ctl performSelector:#selector(yourMethod) withObject:dictSubPoses];
}
in .h file
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
//Set Delegate
CLLocationManagerDelegate
// Declare
CLLocationManager *locationManager;
in .m file
-(void)ViewDidLoad
{
locationupadate=YES;
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 100.0f;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if(locationupadate)
{
NSLog(#"%f",newLocation.coordinate.latitude);
lbl.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
}

CLLocationManager startUpdatingLocation using a UIButton

This is the first time I am using CLLocationManager. I am not sure if i am doing the right thing. Correct me if i am wrong.
I initialize the locationManager in my viewDidLoad Method and tell the locationManager to startUpdatingLocation in the same method.
When the delegate receives
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
[locationManager stopUpdatingLocation];
//do stuff with the coordinates
}
to avoid repeated calls to this delegate method.
I have a UIButton where users can click to update the location
//called by user action
-(IBAction)updateLocation{
//start updating delegate
locationManager.delegate=self;
[locationManager startUpdatingLocation];
}
However when the location changes and when I click the UIbutton, the location coordinates donot change at all. :(
What am i doing wrong? Is this the right of doing or should i not stop the locationManager at all ?
Help would be appreciated.
CLLocationManager caches your last location and returns it as soon as you call -startUpdatingLocation. So, you are starting updates, receiving the old location, and then stopping updates.
This isn't how -startUpdatingLocation/-stopUpdatingLocation are meant to be used. As I asked above, what's wrong with calling the delegate method multiple times? If you only want to get the location when the user taps a button, leave the CLLocationManager updating, and just check CLLocationManger's location property when the user taps your button.
If the reason you're trying to avoid multiple calls to the delegate method is because you're worried about power consumption, etc., adjust the desiredAccuracy property of the CLLocationManager with something like: locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters.
All told, it might look something like this...
.h file:
#interface YourController : NSObject <CLLocationManagerDelegate>
#property (nonatomic, retain) CLLocationManager *locationMgr;
#property (nonatomic, retain) CLLocation *lastLocation;
- (IBAction)getNewLocation:(id)sender;
#end
.m file:
#interface YourController
#synthesize locationMgr = _locationMgr;
#synthesize lastLocation = _lastLocation;
- (id)init
{
if (self = [super init]) {
self.locationMgr = [[CLLocationManager alloc] init];
self.locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
self.locationMgr.delegate = self;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if (!self.lastLocation) {
self.lastLocation = newLocation;
}
if (newLocation.coordinate.latitude != self.lastLocation.coordinate.latitude &&
newLocation.coordinate.longitude != self.lastLocation.coordinate.longitude) {
self.lastLocation = newLocation;
NSLog(#"New location: %f, %f",
self.lastLocation.coordinate.latitude,
self.lastLocation.coordinate.longitude);
[self.locationMgr stopUpdatingLocation];
}
}
- (IBAction)getNewLocation:(id)sender
{
[self.locationMgr startUpdatingLocation];
NSLog(#"Old location: %f, %f",
self.lastLocation.coordinate.latitude,
self.lastLocation.coordinate.longitude);
}
- (void)dealloc
{
[self.locationMgr release];
self.locationMgr = nil;
[self.lastLocation release];
self.lastLocation = nil;
[super dealloc];
}
#end
Am assuming you have included #import <CoreLocation/CoreLocation.h> framework to being with. This is the way you start getting location updates.
CLLocationManager *locationMgr = [[CLLocationManager alloc] init];
locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
locationMgr.delegate = self;
[locationMgr startUpdatingLocation];
You are correct here. After this you start getting location updates, here in this delegate-
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// Handle location updates
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
// Handle error
}

Reload TableView Data if user allow or decline get current location

I have CLLocationManager in app. So what i need is method to know did a user allow or decline current location. According users answer TableController adding value in table in specific way. I tried to [sightsTableView reloadData]; in
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation but after i choose allow or decline tableview is not reloading. I checked Apple's CLLocation reference and couldn't find something useful.
UPD:here is codde sample.
- (void)viewDidLoad {
super viewDidLoad];
[[self locationManager] startUpdatingLocation];
[tempTableView reloadData];
}
- (CLLocationManager *)locationManager {
if (locationManager != nil) {
return locationManager;
}
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager setDelegate:self];
return locationManager;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(#"User allow get location");
self.locationError = NO;
[tempTableView reloadData];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
NSLog(#"User declined get location");
self.locationError = YES;
[tempTableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
.... some big code about a sells )...
cell.textLabel.text = array.title;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if(self.locationError == NO){
cell.detailTextLabel.text = #"!";
}
return cell;
}
UPDATE:
Actually there is no problem with reload. I got that i have problem with refresh table view. If i start to scroll table cell shows new value.
SECOND UPDATE
Now the table is refreshing. The issue was how i called UITableView. I used [tempTableView reloadData];, but it's didn't work for me, so i tried to use this [self.tableView reloadData]; and now it's RELOADING values and REFRESHING it.
locmanager = [[CLLocationManager alloc] init];
[locmanager setDelegate:self];
[locmanager setDesiredAccuracy:kCLLocationAccuracyBest];
if (!locmanager.locationServicesEnabled)
{
[contentView setText:#"Location Services Are Not Enabled"];
return;
}
Have you set a breakpoint and confirmed that the code to reload the table view's data is actually being run? If it isn't being run, are you sure that you've set your view controller as the CLLocationManager's delegate?
To detect if the user declined to allow you to get their current location, you can implement locationManager:didFailWithError: and see if the error's code is kCLErrorDenied.
Update
I big part of your problem is these lines
BOOL locationError = NO;
BOOL locationError = YES;
That's creating a new variable that just lives in that method, instead of setting the locationError variable that lives in your class. You either want to remove the BOOL or do self.locationError = NO;

Capturing current location and calculating distance

I've been looking at this for a while. I've found plenty of posts and looked at the documentation but I'm having trouble getting it working. I have core location implemented, and its working with no problems i.e.
NSLog(#"Description: %#\n", [newLocation description]);
The description details are displayed in the log.
I want to capture the current location when the user taps on a button and as they start to move recapture their location intermittently. Using this information I want to calculate the distance between the starting point and the current point.
I know I can use the following:
CLLocationDistance distance = [myLocation distanceFromLocation:restaurantLocation]
to calculate the distance but I'm not sure how to capture the current location.
If anyone could post some sample code that would be great. I close to getting this working, just need a final push over the line.
Regards,
Stephen
Part 2: Since the original post, I've made a bit of progess. Details posted below:
#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
{
[self.delegate locationUpdate:newLocation];
CLLocation *item1 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
CLLocation *item2 = [[CLLocation alloc] initWithLatitude:oldLocation.coordinate.latitude longitude:oldLocation.coordinate.longitude];
int meters = [item1 getDistanceFrom:item2];
NSLog(#"Distance-d: %d", meters);
[item1 release];
[item2 release];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
}
- (void)dealloc {
[self.locationManager release];
[super dealloc];
}
#end
Am I right to calculate the distance here or should I be doing it in NewWorkoutViewController.m, in the locationUpdate method ?
You set a delegate on your location manager which will be called when the location changes. You can control (indirectly) how often it gets called by specifing a distance filter so that you will only get a callback if the location has moved at least that amount.