Incompatible pointer types assigning to CLLocationManager - cllocationmanager

So I've developed a standalone compass app (arrow revolving to point tofixed lat/long point) which works perfectly as a standalone project but when I've come to incorporate it into the wider project I get a problem.
Initially I get a semantic warning (Incompatible pointer types assigning to 'CLLocationManager*' from 'CLLoccation *__strong') for:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if (newLocation.horizontalAccuracy >= 0) {
self.recentLocation = newLocation; (WARNING HERE)
CLLocation *POI2location = [[CLLocation alloc]
initWithLatitude:kPOI2Latitude
longitude:kPOI2Longitude];
CLLocationDistance delta = [POI2location
distanceFromLocation:newLocation];
And further on I get a fatal error (Property 'coordinate' not found on object of type 'CLLocationManager) for:
- (void)locationManager:(CLLocationManager *)manager
didUpdateHeading:(CLHeading *)newHeading {
if (self.recentLocation != nil && newHeading.headingAccuracy >= 0) {
CLLocation *POI2Location = [[CLLocation alloc]
initWithLatitude:kPOI2Latitude
longitude:kPOI2Longitude];
double course = [self headingToLocation:POI2Location.coordinate
current:recentLocation.coordinate]; (WARNING HERE)
For some reason it doesn't like 'recentLocation' now whereas it was all working perfectly before. Can someone point out to me what I'm missing. I'm sure it's obvious to someone with more experience than me.
Many thanks in advance.

Started again this morning and the answer is staring me in the face!
In the .h file i'd put
#property (strong, nonatomic) CLLocationManager *recentLocation;
when I should have put
#property (strong, nonatomic) CLLocation *recentLocation;

Related

Comparing speed values issue(what ever i am getting from CLLocationManager)

I am having little bit confused regarding this way of asking question
Any how i am mentioning my query with support of image here. Can you please help me out regarding this issue
Step 1: I have an requirement like: By using CLLocationManger delegate methods i fetched speed value like:
- (void)startLocationUpdates{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.pausesLocationUpdatesAutomatically = YES;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
}
#pragma mark
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations{
float speed = locationManager.location.speed;
float speedInKmph = speed * 3.6; // to convert the speed into kmph.
NSString *speedValue =[NSString stringWithFormat:#"%.f Kmph ",speedInKmph];
self.currentSpeedLblRef.text = speedValue;
self.maxSpeedLblRef.text = speedValue;
}
Step 2: currentSpeedLblRef,maxSpeedLblRef --> these are my UILabels
Example: Now i am driving a car --> For the first time i opened the app and i got the current speed of car(like: 120 Kmph) and then i need to display same value in "maxSpeedLblRef"(120 Kmph) also
After some time my current speed of car if 50 Kmph. But i need to display value in "maxSpeedLblRef" is --> Max value --> means 120 kmph . Because already i was getting 120 kmph value for previos
After that If my current speed of car if 180 kmph --> I need to show "maxSpeedLblRef" valu like: 180 Kmph. Because it is the latest one compare to 120 Kmph
After Close the app and then
If i reopen the app i want to show the vale like "maxSpeedLblRef" --> 180 Kmph. Because this value is the previous saved value
HERE IS MY SOURCE CODE:Click here link
you are missing a few simple things here!
You need to store the max speed for comparison - all you're doing here is is updating the label with the current value every time. Set up a class-level attribute, initial value = 0, and update it whenever current speed > max speed.
There are a few ways you can store the max value so that it's there when you next open the app. Probably easiest to go with user defaults. There are many tutorials available - try this one http://code.tutsplus.com/tutorials/ios-sdk-working-with-nsuserdefaults--mobile-6039
OK - using your project code, here's what you need.
Update your ViewController.h to this
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *currentSpeedLblRef;
#property (weak, nonatomic) IBOutlet UILabel *maxSpeedLblRef;
// you need to store the max speed
#property float speedMax;
-(void)loadDefaults;
-(void)storeDefaults;
#end
and then in the VIewController.m, replace the viewDidLoad with this
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self loadDefaults];
[self startLocationUpdates];
}
update the locationManager function to this
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations{
float speed = locationManager.location.speed;
float speedInKmph = speed * 3.6; // to convert the speed into kmph.
NSString *speedValue =[NSString stringWithFormat:#"%.f Kmph ",speedInKmph];
self.currentSpeedLblRef.text = speedValue;
if (speedInKmph > self.speedMax)
{
self.speedMax = speedInKmph;
[self storeDefaults];
}
NSString *speedMaxValue =[NSString stringWithFormat:#"%.f Kmph ",self.speedMax];
self.maxSpeedLblRef.text = speedMaxValue;
}
and, finally add the load / store functions
- (void)loadDefaults
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.speedMax = [defaults floatForKey:#"SpeedMax"];
}
- (void)storeDefaults
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setFloat:self.speedMax forKey:#"SpeedMax"];
[defaults synchronize];
}

How to get information printed in Xcode's console onto screen?

I started using Xcode a couple days ago and I'm completely lost. I'm trying to get a GPS locator app running found here.
Basically, the app prints any updated GPS information using NSLog, which as far as my understanding goes, prints to Xcode's console. However, I'd like to get this info printed onto the screen.
Here's the code from CFAStartViewController.m that successfully prints to the screen:
-(void)viewDidAppear:(BOOL)animated{
CFAAppDelegate *appDelegate=(CFAAppDelegate *)[UIApplication sharedApplication].delegate;
CLLocation *currentLocation=appDelegate.locationManager.location;
self.labelLocationInformation.text=[NSString stringWithFormat:#"latitude: %+.6f\nlongitude: %+.6f\naccuracy: %f",
currentLocation.coordinate.latitude,
currentLocation.coordinate.longitude,
currentLocation.horizontalAccuracy];
}
And here's the code in CFAAppDelegate.m that successfully prints to the console:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0)
{
//Location timestamp is within the last 15.0 seconds, let's use it!
if(newLocation.horizontalAccuracy<35.0){
//Location seems pretty accurate, let's use it!
NSLog(#"latitude %+.6f, longitude %+.6f\n",
newLocation.coordinate.latitude,
newLocation.coordinate.longitude);
NSLog(#"Horizontal Accuracy:%f", newLocation.horizontalAccuracy);
//Optional: turn off location services once we've gotten a good location
//[manager stopUpdatingLocation];
}
}
}
I tried changing the calls to NSLog to self.labelLocationInformation.text, with a similar format to that of CFAStartViewController, but it doesn't seem to do anything. I've read through the basic tutorials of Xcode, but I feel there's some knowledge lacking (obviously) on what to do overall.
If the best you could do is post a link that helps me solve this problem, that would be great.
I think the problem is due to scope - the didUpdateToLocation: method is sent to the location manager delegate, ie your app delegate, which doesn't have the label in scope. Try changing your delegate for the location manager to be your CFAStartViewController, and move the associated location manager delegate code from App Delegate to CFAStartViewController. Then the label will be in scope when didUpdateToLocation: is called.
Based on your clarifying response to my comment.... If you want the data from CFAAppDelegate to be presented in your CFAStartViewController then you need to send that data to CFAStartViewController (or CFAStartViewController needs to get it). To send it 1) provide a storyboard id for CFAStartViewController such as "CFAVC". 2) define or expose properties in CFAStartViewController to contain your data. 3) instantiate CFAStartViewController via the following from within CFAAppDelegate:
// in CFAStartViewController.h define property such as:
#property (strong, nonatomic) CLLocation *incomingLocation;
// in CFAAppDelegate.m
// get a pointer to your VC
CFAStartViewController *destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:#"CFAVC"];
// set properties on VC
destinationVC.incomingLocation = newLocation;
// show CFAStartViewController (or use whatever method you are currently using)
[self.navigationController pushViewController:destinationVC animated:YES];

Mapkit, MKDirections, voice narration,

I am working on an iOS 7 app that uses mapkit, and I can route and pot directions for users.
I am trying to recreate the exact same way the apple maps app works when starting a trip, with the voice coming up and narrating the steps, and the camera movements. I don;t know whether thats possible and where can I find classes that expose that.
Thanks.
About the narrating, I don't know. But for the traking of the user, and the camera movements, I used this library: https://github.com/100grams/CoreLocationUtils
There is a lot of helpers, I'm sure it could help you ;)
To rotate the view, you have to start the heading, like this:
// some code
[self.locationManager startUpdatingHeading];
// some code
Then, implement this delegate method:
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
if (newHeading.headingAccuracy > 0 && abs(self.over-newHeading.trueHeading) > 3) {
CGFloat north = -1.0f * M_PI * (newHeading.trueHeading) / 180.0f;
CGFloat bearing = -1.0f * M_PI * (newHeading.trueHeading-self.bearing) / 180.0f;
/* do some verifications here
you can make the rotation here using CGAffineTransformMakeRotation(north)
or CGAffineTransformMakeRotation(bearing )
*/
self.over = newHeading.trueHeading;
}
}
Finaly, in this delegate method, you can get the bearing value between 2 coordinates using the library (previously mentionned):
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
self.currentUserLocation = newLocation;
// set the target location...
self.bearing = [CLLocation directionFromCoordinate:self.currentUserLocation.coordinate toCoordinate:self.targetLocation.coordinate];
}
Hope that will help you ;)
This features private to Apple Maps App.
You can just use maps or create this features by yourself.
Check out OpenEars for a narration option.
In iOS 7 and above, MKMapCamera and its animation ability will help you greatly with the actual stepping through on your map view.

iOS how can I get CLLocation in persistent state

I'm trying to get a CLLocation property to store a location MKMapView. this part of my code:
on my .h
#property (retain, nonatomic) CLLocation *currentlocation;
on my .m
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if ((_currentlocation.coordinate.longitude == 0 ) && (_currentlocation.coordinate.latitude == 0) )
{
self.currentlocation = [self.mapView.userLocation.location copy];
}
The problem is every time is trying to update the location the "self.currentlocation" is 0. My question how can I retain the value of self.currentlocation ?
I'll really appreciate your help.
Try to replace the 0 with "nil".
Now the if statement checks, if your variable is empty and not if it is 0.
I resolve my problem using CLLocationCoordinate2D to store the coordenates store in self.mapView.userLocation.location.

method not called from app delegate in ios

I want to call a method from elsewhere in the app to get the user's location that was obtained in the app delegate. When calling CLLocation *getCurLoc = [AppDelegate getCurrentLocation]; from another view controller, nothing is returned.
The App Delegate is,
#synthesize locationManager;
CLLocation *location;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.desiredAccuracy=kCLLocationAccuracyKilometer;
[locationManager startUpdatingLocation];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[locations lastObject];
[manager stopUpdatingLocation];
CLLocation *location = [locations lastObject];
}
+(CLLocation *)getCurrentLocation{
return location;
}
Changing it to an instance method with a "-" didn't work. Should "location" be made into an instance? Should the delegate be made into an instance, or is there a better way to access it from elsewhere?
In didUpdateLocations, you define and set a local variable location, not the global variable location defined at the top of the file. Changing the line
CLLocation *location = [locations lastObject];
to
location = [locations lastObject];
would fix the problem. But the better solution is to use a property in the AppDelegate class.
You can define it in a class extension:
#interface AppDelegate ()
#property(strong, nonatomic) CLLocation *location;
#end
Then you access it in instance methods like
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[locations lastObject];
[manager stopUpdatingLocation];
self.location = [locations lastObject];
}
and in a class method like
+(CLLocation *)getCurrentLocation{
// Get the instance:
AppDelegate *app = [[UIApplication sharedApplication] delegate];
return app.location;
}
Update: If the AppDelegate is declared to conform so some protocol (in the
public interface or in the class extension), for example:
#interface AppDelegate () <CLLocationManagerDelegate>
#property(strong, nonatomic) CLLocation *location;
#end
then the above code creates a warning
initializing 'AppDelegate *__strong' with an expression of incompatible type 'id<UIApplicationDelegate>'
and an explicit cast is necessary:
+(CLLocation *)getCurrentLocation{
// Get the instance:
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
return app.location;
}
Martin's answer is an effective quick&dirty way of solving this problem in a way that is consistent with your approach - storing the location in appDelegate.
If you want to take a step further you might want to consider implementing a special object that would hold the data - the data model. It is considered a bad practice to store data in application delegate - it is not what it is there for (though it works perfectly fine in sample or small applications).
You could do something like this:
DataModel.h
#import <Foundation/Foundation.h>
#interface DataModel : NSObject
#property (strong) CLLocation *location;
+ (DataModel *)sharedModel;
#end
DataModel.m
#import "DataModel.h"
#class CLLocation;
#implementation DataModel
- (id) init
{
self = [super init];
if (self)
{
_location = nil;
}
return self;
}
+ (DataModel *)sharedModel
{
static DataModel *_sharedModel = nil;
static dispatch_once_t onceSecurePredicate;
dispatch_once(&onceSecurePredicate,^
{
_sharedModel = [[self alloc] init];
});
return _sharedModel;
}
#end
You would then need to #import "DataModel.h" wherever you need it. You would change your didUpdateLocations: to:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
[locations lastObject];
[manager stopUpdatingLocation];
[DataModel sharedInstance].location = [locations lastObject];
}
And from anywhere in the code you could get this location simply by [DataModel sharedInstance].location.
EDIT:
For a very simple app this approach might look as an overkill. But as soon as your app grows it surely pays off to use it.
This kind of class/object/singleton is ment to hold all the data your app needs (fixed and temporary). So all the data sources can make a good use of it. In short: it enables you to easily follow the model-view-controller guidelines.
You cold of course use another class/object/singleton to hold the temporary data - it depends on the complexity of your data-structure.
You don't have to specifically initialize this kind of object. It is initialized the first time you reference it. That is why dispatch_once is there for. It makes sure that there is one and only one instance of this shared object present: https://stackoverflow.com/a/9119089/653513
And this one single instance of [DataModel sharedInstance] will remain there until your app is terminated.
Apple uses similar approach for [NSUserDefaults standardDefaults], [UIApplication sharedApplicaton] for example.
I tend to put the #import "DataModel.h" into my projects Prefix.pch so I don't have to import it every single time I use it (it is used trough all the app).
PROS:
- data accesible throughout the app
- code reusability
- MVC structure
- code is more readable
CONS:
- I couldn't really find one. Except that the dispatch_once(&onceSecurePredicate,^... might confuse one for the first couple of seconds.
You can access the AppDelegate from any point in your application using [UIApplication sharedApplication].delegate so you could do:
CLLocation *location = [(YourAppDelegateClassName*)[UIApplication sharedApplication].delegate getCurrentLocation];
The method getCurrentLocation needs to be an instance method (-(CLLocation *)getCurrentLocation). You will need also to import #import "YourAppDelegateClassName.h" in those files you need to use that method.
To avoid the casting and accessing [UIApplication sharedApplication].delegate everytime I prefer to implement a static method in my AppDelegates:
+ (YourAppDelegateClassName*)sharedDelegate {
return (YourAppDelegateClassName*)[UIApplication sharedApplication].delegate;
}
So you can use any method like this:
CLLocation *location = [[YourAppDelegateClassName sharedDelegate] getCurrentLocation];

Resources