I'm trying to follow this tutorial:
http://www.appcoda.com/how-to-get-current-location-iphone-user/
Everything is fine till I add this line:
locationManager = [[CLLocationManager alloc] init];
Then I get the error.
I also get errors for these lines: (Xcode suggests I use "_LongitudeLabel"?
if (currentLocation != nil) {
longitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
latitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
Any idea what's wrong? Does the tutorial have errors or have I done something wrong?
Thanks!
This is ViewController.m file:
#import "ViewController.h"
#implementation MyLocationViewController {
CLLocationManager *locationManager;
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
latitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
#end
This is ViewController.h file:
// ViewController.h
// MyLocationDemo
//
// Created by Ian Nicoll on 12/11/14.
// Copyright (c) 2014 Ian Nicoll. All rights reserved.
//
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *LatitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *LongitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *addressLabel;
- (IBAction)getCurrentLocation:(id)sender;
#end
#interface MyLocationViewController : UIViewController <CLLocationManagerDelegate>
#end
The first issue is an error on your part. You declared locationManager in MyLocationViewController but try to initialize it in the viewDidLoad of ViewController, where it of course does not exist.
The second issue is an issue with the instructions. When you declare an #property, the default behavior is to create an instance variable with an underscore in front of it.
So #property (weak, nonatomic) IBOutlet UILabel *LatitudeLabel; can be accessed as self.latitudeLabel (which goes through the setter/getter) or just _latitudeLabel which accesses the ivar directly. The latter is probably what you want.
Ok so the build now is Succeeded (though I'm not 100& sure I got things right) but now I get a warning for this line: locationManager.delegate = self; - Assigning to 'id'from incompatible type 'ViewControler *const_strong'
Would you know how to fix this warning?
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController {
CLLocationManager *locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
_LongitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
_LatitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
#end
Related
//ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet UILabel *addresslbl;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
//Viewcontroller.m
#import "ViewController.h"
#interface ViewController ()
{
CLLocationManager *locationManager;
CLLocationCoordinate2D updateLocation;
NSString *strAddress;
CLGeocoder *geocoder;
}
#end
#implementation ViewController
#define AzaveaCoordinate CLLocationCoordinate2DMake(19.167391, 73.247686)
- (void)viewDidLoad {
[super viewDidLoad];
[_mapView setRegion:MKCoordinateRegionMake(AzaveaCoordinate, MKCoordinateSpanMake(0.010, 0.010)) animated:YES];
geocoder = [[CLGeocoder alloc]init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager requestWhenInUseAuthorization];
self.mapView.delegate = self;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
CLLocation *location = [[CLLocation alloc]initWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
[self geocode:location];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
{
CLLocation *currentLocation = newLocation;
self.mapView.centerCoordinate = currentLocation.coordinate;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(currentLocation.coordinate,1500,1500);
[self.mapView setRegion: region animated:true];
[self geocode:currentLocation];
}
-(void)geocode:(CLLocation *)location
{
// geocoder = [[CLGeocoder alloc]init];
[geocoder cancelGeocode];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *data, NSError *error)
{
CLPlacemark *placemark = [data lastObject];
NSDictionary * addressDict = placemark.addressDictionary;
NSArray * addressList = addressDict[#"FormattedAddressLines"];
NSString * address = [NSString stringWithFormat:#"%#,%#,%#",addressList[0],addressList[1],addressList[2]];
NSLog(#" Address is :%#",address);
self.addresslbl.text = address;
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is the moveable map code like ola and uber. Means when i move the map, at that time the map pin is noted, the noted pin is given me address of the that particular area like city, state, pincode etc in label, but i want only the longitude, latitude value of this address in label.
so please help me about this code. How can i get the longitude latitude value in ?
Assuming that the label that you want to is self.addresslbl, change this method:
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
CLLocation *location = [[CLLocation alloc]initWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
[self geocode:location];
}
To:
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
self.addresslbl.text = [NSString stringWithFormat:#"%f, %f", mapView.centerCoordinate.longitude, mapView.centerCoordinate.latitude];
}
Here is the code, it all works fine but each time I hit the "Get My Location" button it updates the location twice, I cannot find the reason why, any idea's? I have removed much code from below this and it still does it so I know it's in this part somewhere. Thanks.
.h file:
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *LatitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *LongitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *GPSAccuracyLabel;
#property (weak, nonatomic) IBOutlet UILabel *AltitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *VerticalAccuracyLabel;
- (IBAction)getCurrentLocation:(id)sender;
#end
#interface MyLocationViewController : UIViewController <CLLocationManagerDelegate>
#end
.m file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController {
CLLocationManager *locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = (id)self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error); UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil]; [errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Location updated: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
_LatitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
_LongitudeLabel.text = [NSString stringWithFormat:#"%.6f", currentLocation.coordinate.longitude];
_GPSAccuracyLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.horizontalAccuracy];
_AltitudeLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.altitude];
_VerticalAccuracyLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.verticalAccuracy];
}
Console output each time I press the button:
2014-11-22 23:49:37.539 MyLocationDemo[914:60b] Location updated: <+10.16863927,+124.75859298> +/- 10.00m (speed 0.00 mps / course -1.00) # 22/11/14 11:49:37 pm Philippine Standard Time
2014-11-22 23:49:37.545 MyLocationDemo[914:60b] Location updated: <+10.16863927,+124.75859298> +/- 10.00m (speed 0.00 mps / course -1.00) # 22/11/14 11:49:37 pm Philippine Standard Time
After a quick look at Apple's documentations, I've noticed that the delegate method you are using, - locationManager:didUpdateToLocation:fromLocation: is deprecated since iOS 6.
Instead, you should use - locationManager:didUpdateLocations:.
Try replacing your code with the code below and see if it make any difference:
EDIT- I've edit the code below to handle the double-call you get.
From your post above I see they are almost simultaneously, So basically we'll check if at least 1 seconds has passed since last call.
There are probably better ways to do it, but that was just at the top of my head...
Haven't checked it in Xcode, but, if I haven't made a typo or something, it should work.
// ViewController.m
#interface ViewController ()
#property (nonatomic, strong) NSDate *lastUpdateTime; // Create a property
#end // to hold current time
- (void)viewDidLoad {
[super viewDidLoad];
self.lastUpdateTime = [NSDate date]; // In viewDidLoad, 'initialize' it
// to get the current time
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
NSTimeInterval passedTime = -[self.lastUpdateTime timeIntervalSinceNow];
// Here we are checking how much seconds have passed since our lastUpdateTime
// Since lastUpdateTime is in the past, the result will be negative, therefore
// the minus sign, so we'll get a positive number
if(passedTime < 1) {
return;
} // Now we check if less than one second have passed. If so, the whole method
// will return. If not, it will just continue executing
CLLocation *currentLocation = [locations lastObject];
self.lastUpdateTime = [NSDate date]; // Don't forget to update the lastUpdateTime
// To hold the new update time
if (currentLocation != nil) {
NSLog(#"Location updated: %#", currentLocation);
_LatitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
_LongitudeLabel.text = [NSString stringWithFormat:#"%.6f", currentLocation.coordinate.longitude];
_GPSAccuracyLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.horizontalAccuracy];
_AltitudeLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.altitude];
_VerticalAccuracyLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.verticalAccuracy];
}
}
#AMI289, your idea worked, no more double call.
I post the final code here in case it helps others, I just added back the locationManager = [[CLLocationManager alloc] init];.
// ViewController.m
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) NSDate *lastUpdateTime; // create a property to hold current time.
#end
#implementation ViewController {
CLLocationManager *locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.lastUpdateTime = [NSDate date]; // In viewDidLoad, 'initialize' it to get the current time
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = (id)self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
NSTimeInterval passedTime = -[self.lastUpdateTime timeIntervalSinceNow];
// Here we are checking how much seconds have passed since our lastUpdateTime
// Since lastUpdateTime is in the past, the result will be negative, therefore
// the minus sign, so we'll get a positive number
if(passedTime < 1) {
return;
} // Now we check if less than one second have passed. If so, the whole method
// will return. If not, it will just continue executing
CLLocation *currentLocation = [locations lastObject];
self.lastUpdateTime = [NSDate date]; // Don't forget to update the lastUpdateTime
// To hold the new update time
if (currentLocation != nil) {
NSLog(#"Location updated: %#", currentLocation);
_LatutideLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
_LongitudeLabel.text = [NSString stringWithFormat:#"%.6f", currentLocation.coordinate.longitude];
_GPSAccuracyLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.horizontalAccuracy];
_AltitudeLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.altitude];
_VerticalAccuracyLabel.text = [NSString stringWithFormat:#"%.2f", currentLocation.verticalAccuracy];
}
// Stop Location Manager
[locationManager stopUpdatingLocation];
}
#end
I'm following the MVCS paradigm for saving and then loading instances of data objects in a Test app related to updating mapping data.
BNRMapPoint.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface BNRMapPoint : NSObject<MKAnnotation, NSCoding>
{
double latitude;
double longitude;
#public NSArray *mapPoints;
}
-(id) initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subTitle:(NSString *)st;
//this is required property in MKAnnotation Protocol
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
//this is an optional property in MKAnnotation Protocol
#property (nonatomic, copy) NSString *title;
//this is an optional property in MKAnnotation Protocol
#property (nonatomic,readonly,copy) NSString *subTitle;
#end
BNRMapPoint.m (Model)
#import "BNRMapPoint.h"
#implementation BNRMapPoint
#synthesize coordinate=_coordinate;
#synthesize title=_title;
#synthesize subtitle=_subtitle;
-(void)encodeWithCoder:(NSCoder *)aCoder{
latitude = self.coordinate.latitude;
longitude = self.coordinate.longitude;
[aCoder encodeObject:self.title forKey:#"title"];
[aCoder encodeObject:_subTitle forKey:#"subTitle"];
[aCoder encodeDouble: latitude forKey:#"latitude"];
[aCoder encodeDouble:longitude forKey:#"longitude"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self= [super init]) {
[self setTitle:[aDecoder decodeObjectForKey:#"title"]];
self->_subTitle= [aDecoder decodeObjectForKey:#"subTitle"];
latitude= [aDecoder decodeDoubleForKey:#"latitude"];
longitude= [aDecoder decodeDoubleForKey:#"longitude"];
}
return self;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subTitle:(NSString *)st{
if (self= [super init]) {
self.coordinate=c;
self.title=t;
_subtitle=st;
}
return self;
}
-(id) init{
return [self initWithCoordinate:CLLocationCoordinate2DMake(43.07, -89.32) title:#"Hometown" subTitle:self.subtitle];
}
#end
WhereamiViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#import "BNRMapPoint.h"
#import "RootObject.h"
#interface WhereamiViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate,UITextFieldDelegate>
{
#public RootObject *rootObj;
CLLocationManager *locationManager;
IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
IBOutlet UITextField *locationTitleField;
}
-(IBAction)buttonDidGetPressed:(id)sender;
-(BOOL)textFieldShouldReturn:(UITextField *)textField;
-(void)findLocation;
-(void)foundLocation:(CLLocation *)loc;
#end
WhereamiViewController.m (ViewController)
#import "WhereamiViewController.h"
#interface WhereamiViewController ()
#end
#implementation WhereamiViewController
-(IBAction)buttonDidGetPressed:(UISegmentedControl *)sender{//Silver challenge
NSLog(#"%#",NSStringFromSelector(_cmd));
if([sender selectedSegmentIndex]==0){
[worldView setMapType:MKMapTypeStandard];
}
else if([sender selectedSegmentIndex]==1){
[worldView setMapType:MKMapTypeHybrid];
}
else if([sender selectedSegmentIndex]==2){
[worldView setMapType:MKMapTypeSatellite];
}
}
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
NSLog(#"%#", NSStringFromSelector(_cmd));
if (self=[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
rootObj= [[RootObject alloc] init];
locationManager= [[CLLocationManager alloc] init];
[locationManager setDelegate:self];//self is Whereamicontroller. The delegate pointer is of type id<CLLocationManagerDelegate> and is an ivar of CLLocationManager.
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
NSLog(#"test");
return self;
}
-(void) viewDidLoad{
// [worldView setMapType:MKMapTypeSatellite]; Bronze challenge
[worldView setShowsUserLocation:YES];
}
-(void)findLocation{
NSLog(#"%#",NSStringFromSelector(_cmd));
[locationManager startUpdatingLocation];//This calls locationManager:didUpdateLocations:
NSLog(#"location updated");
[activityIndicator startAnimating];
[locationTitleField setHidden:YES];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"%#",NSStringFromSelector(_cmd));
[self findLocation];
[textField resignFirstResponder];
return YES;
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
NSLog(#"%#",NSStringFromSelector(_cmd));
CLLocationCoordinate2D centerCoordinate= [[userLocation location] coordinate]; //get the coordinate of current location.
MKCoordinateSpan span= MKCoordinateSpanMake(250, 250);//Structure members
MKCoordinateRegion mapPortionToDisplay= MKCoordinateRegionMakeWithDistance(centerCoordinate, span.latitudeDelta, span.longitudeDelta);//span.latitudeDelta=250 and span.longitudeDelta=250
[worldView setRegion:mapPortionToDisplay animated:YES];
// [worldView setRegion:mapPortionToDisplay];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
NSLog(#"%#",NSStringFromSelector(_cmd));
NSLog(#"Heading %#",newHeading);
}
-(void)foundLocation:(CLLocation *)loc{
NSLog(#"%#",NSStringFromSelector(_cmd));
CLLocationCoordinate2D coord= [loc coordinate];
NSDateFormatter *formatter= [[NSDateFormatter alloc] init];
NSDate *currentDate= [[NSDate alloc] init];
[formatter setDefaultDate:currentDate];
BNRMapPoint *bmp= [[BNRMapPoint alloc] initWithCoordinate:coord title:[locationTitleField text] subTitle:[[formatter defaultDate] description]];
[rootObj.mapPoints addObject:bmp];
[worldView addAnnotation:bmp];
MKCoordinateRegion region= MKCoordinateRegionMakeWithDistance(coord,250,250);
[worldView setRegion:region animated:YES];
//RESET the UI
[locationTitleField setText:#" "];
[activityIndicator stopAnimating];
[locationTitleField setHidden:NO];
[locationManager stopUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ //CLLocationManagerDelegate method implementation
NSLog(#"%#", NSStringFromSelector(_cmd));
// NSTimeInterval t0=[[locations lastObject] timeIntervalSinceNow];
NSLog(#"%#",(CLLocation *)[locations lastObject]);
NSTimeInterval t= [[(CLLocation *)[locations lastObject] timestamp] timeIntervalSinceNow];
if (t<-180) {
return; //No op
}
[self foundLocation:[locations lastObject]];
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"Could not find location: %#",error);//CLLocationManagerDelegate method implementation
}
#end
RootObject.h
#import <Foundation/Foundation.h>
#interface RootObject : NSObject
#property NSMutableArray *mapPoints;
-(BOOL)saveChanges;
-(NSString *)dataObjectArchivePath;
#end
RootObject.m (Store)
#import "RootObject.h"
#implementation RootObject
#synthesize mapPoints;
-(NSString *)dataObjectArchivePath{
NSArray *documentDirectories= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory= [documentDirectories objectAtIndex:0];
NSString *finalPath= [documentDirectory stringByAppendingPathComponent:#"items.archive"];
return finalPath;
}
-(BOOL)saveChanges{
NSString *path= [self dataObjectArchivePath];
return [NSKeyedArchiver archiveRootObject:self.mapPoints toFile:path];writing to the file items.archive
}
-(id)init{
if (self=[super init]) {
NSString *path= [self dataObjectArchivePath];
self.mapPoints= [NSKeyedUnarchiver unarchiveObjectWithFile:path];//reading from the file items.archive
if (!self.mapPoints) {
self.mapPoints= [[NSMutableArray alloc] init];
}
}
return self;
}
#end
AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
NSLog(#"%#",NSStringFromSelector(_cmd));
BOOL success= [[BNRItemStore sharedStore] saveChanges];
if (success) {
NSLog(#"Saved all of the BNRItems");
}
else{
NSLog(#"Could not save any of the BNRItems");
}
}
In the above code, the saveChanges method is called from application: didEnterBackground:. So i haven't made a singleton object for the Store (RootObject). But i instantiated it in the designated initializer of viewController. The data to be archived is BNRMapPoint objects. On the entering background state, the code did save the objects successfully. However after the relaunching the app, the initWithCoder is where its getting stuck. The app crashes when it comes to reading the previously saved MapPoint objects. Pls help.. I've checked almost possible. Don't know what to do. I'm stuck.
So the problem is that you have:
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
And you are trying to use setter on read only property:
self.coordinate=c;
This is why it says that unrecognized selector is send - becuase it's readonly so setter doesn't exists. Using property this was is the same as calling:
[self setCoordinate:c]
Just make property assignable
My custom class needs to receive the "didUpdateToLocation" CLLocationManagerDelegate method, however i can't seem to make the following code work.
Header file.
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface MyCurrentLocation : NSObject<MKAnnotation,CLLocationManagerDelegate,MKMapViewDelegate>
{
CLLocationCoordinate2D coordinate;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) CLLocationManager *locationManager;
-(MyCurrentLocation *)init;
#end
Implementation file.
#import "MyCurrentLocation.h"
#implementation MyCurrentLocation
-(BLCurrentLocation *)init
{
self = [super init];
if (self) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[_locationManager startUpdatingLocation];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Did we receive a location?");
}
You have to respond to other delegate methods, such as the error callback. Also, check for the CLLocationManager's + (CLAuthorizationStatus)authorizationStatus class method to determine if you are able to use location services.
I don't know why but maybe you can try to implement this delegate method to see if location service cannot be registered.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please make sure Location Service is ON" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertView show];
}
I'm trying to create an app in Xcode 4 based on geofencing. The app will notify the user when entering a region with certain center coordinates and a certain radius given in meters. All my regions are saved in a p-list. However I get multiple callbacks and more locations than I want gets called (i.e. locations not even in the right location gets called. Below you can see our code. I have also added a kml-layer which you can ignore because it has nothing to do with the fencing. My p-list is an array and contains of 20 items with the type dictionary and the keys are title, latitude, longitude and radius. The radius is set to 50 meters.
ViewController.h
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#implementation ViewController
#synthesize coordinateLabel;
#synthesize mapView;
CLLocationManager *_locationManager;
NSArray *_regionArray;
- (void)viewDidLoad
{
[super viewDidLoad];
[self initializeMap];
[self initializeLocationManager];
NSArray *geofences = [self buildGeofenceData];
[self initializeRegionMonitoring:geofences];
[self initializeLocationUpdates];
}
- (void)viewDidUnload
{
[self setCoordinateLabel:nil];
[self setMapView:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)initializeMap {
CLLocationCoordinate2D initialCoordinate;
initialCoordinate.latitude = 41.88072;
initialCoordinate.longitude = -87.67429;
[self.mapView setRegion:MKCoordinateRegionMakeWithDistance(initialCoordinate, 400, 400) animated:YES];
self.mapView.centerCoordinate = initialCoordinate;
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
}
- (void)initializeLocationManager {
// Check to ensure location services are enabled
if(![CLLocationManager locationServicesEnabled]) {
[self showAlertWithMessage:#"You need to enable location services to use this app."];
return;
}
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
}
- (void) initializeRegionMonitoring:(NSArray*)geofences {
if (_locationManager == nil) {
[NSException raise:#"Location Manager Not Initialized" format:#"You must initialize location manager first."];
}
if(![CLLocationManager regionMonitoringAvailable]) {
[self showAlertWithMessage:#"This app requires region monitoring features which are unavailable on this device."];
return;
}
for(CLRegion *geofence in geofences) {
[_locationManager startMonitoringForRegion:geofence];
}
}
- (NSArray*) buildGeofenceData {
NSString* plistPath = [[NSBundle mainBundle] pathForResource:#"regions" ofType:#"plist"];
_regionArray = [NSArray arrayWithContentsOfFile:plistPath];
NSMutableArray *geofences = [NSMutableArray array];
for(NSDictionary *regionDict in _regionArray) {
CLRegion *region = [self mapDictionaryToRegion:regionDict];
[geofences addObject:region];
}
return [NSArray arrayWithArray:geofences];
}
- (CLRegion*)mapDictionaryToRegion:(NSDictionary*)dictionary {
NSString *title = [dictionary valueForKey:#"title"];
CLLocationDegrees latitude = [[dictionary valueForKey:#"latitude"] doubleValue];
CLLocationDegrees longitude =[[dictionary valueForKey:#"longitude"] doubleValue];
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude, longitude);
CLLocationDistance regionRadius = [[dictionary valueForKey:#"radius"] doubleValue];
return [[CLRegion alloc] initCircularRegionWithCenter:centerCoordinate
radius:regionRadius
identifier:title];
}
- (void)initializeLocationUpdates {
[_locationManager startUpdatingLocation];
}
#pragma mark - Location Manager - Region Task Methods
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"Entered Region - %#", region.identifier);
[self showRegionAlert:#"Entering Region" forRegion:region.identifier];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Exited Region - %#", region.identifier);
[self showRegionAlert:#"Exiting Region" forRegion:region.identifier];
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Started monitoring %# region", region.identifier);
}
#pragma mark - Location Manager - Standard Task Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
self.coordinateLabel.text = [NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude, newLocation.coordinate.longitude];
}
#pragma mark - Alert Methods
- (void) showRegionAlert:(NSString *)alertText forRegion:(NSString *)regionIdentifier {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:alertText
message:regionIdentifier
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
}
- (void)showAlertWithMessage:(NSString*)alertText {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Location Services Error"
message:alertText
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}
#end
ViewController.m
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#implementation ViewController
#synthesize coordinateLabel;
#synthesize mapView;
#synthesize kmlParser;
CLLocationManager *_locationManager;
NSArray *_regionArray;
- (void)viewDidLoad
{
[super viewDidLoad];
[self initializeMap];
[self initializeLocationManager];
NSArray *geofences = [self buildGeofenceData];
[self initializeRegionMonitoring:geofences];
[self initializeLocationUpdates];
// Locate the path to the route.kml file in the application's bundle
// and parse it with the KMLParser.
NSString *path = [[NSBundle mainBundle] pathForResource:#"urbanPOIsthlm" ofType:#"kml"];
NSURL *url = [NSURL fileURLWithPath:path];
kmlParser = [[KMLParser alloc] initWithURL:url];
[kmlParser parseKML];
// Add all of the MKOverlay objects parsed from the KML file to the map.
NSArray *overlays = [kmlParser overlays];
[mapView addOverlays:overlays];
// Add all of the MKAnnotation objects parsed from the KML file to the map.
NSArray *annotations = [kmlParser points];
[mapView addAnnotations:annotations];
// Walk the list of overlays and annotations and create a MKMapRect that
// bounds all of them and store it into flyTo.
MKMapRect flyTo = MKMapRectNull;
for (id <MKOverlay> overlay in overlays) {
if (MKMapRectIsNull(flyTo)) {
flyTo = [overlay boundingMapRect];
} else {
flyTo = MKMapRectUnion(flyTo, [overlay boundingMapRect]);
}
}
for (id <MKAnnotation> annotation in annotations) {
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
if (MKMapRectIsNull(flyTo)) {
flyTo = pointRect;
} else {
flyTo = MKMapRectUnion(flyTo, pointRect);
}
}
// Position the map so that all overlays and annotations are visible on screen.
mapView.visibleMapRect = flyTo;
}
- (void)viewDidUnload
{
[self setCoordinateLabel:nil];
[self setMapView:nil];
//DERAS alltså KML!!!
[kmlParser release];
///
[super viewDidUnload];
}
/////Deras alltså KML!!!
#pragma mark MKMapViewDelegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
return [kmlParser viewForOverlay:overlay];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
return [kmlParser viewForAnnotation:annotation];
}
//////////
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)initializeMap {
CLLocationCoordinate2D initialCoordinate;
initialCoordinate.latitude = 59.3353733;
initialCoordinate.longitude = 18.0712647;
[self.mapView setRegion:MKCoordinateRegionMakeWithDistance(initialCoordinate, 400, 400) animated:YES];
self.mapView.centerCoordinate = initialCoordinate;
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
}
- (void)initializeLocationManager {
// Check to ensure location services are enabled
if(![CLLocationManager locationServicesEnabled]) {
[self showAlertWithMessage:#"You need to enable location services to use this app."];
return;
}
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
}
- (void) initializeRegionMonitoring:(NSArray*)geofences {
if (_locationManager == nil) {
[NSException raise:#"Location Manager Not Initialized" format:#"You must initialize location manager first."];
}
if(![CLLocationManager regionMonitoringAvailable]) {
[self showAlertWithMessage:#"This app requires region monitoring features which are unavailable on this device."];
return;
}
for(CLRegion *geofence in geofences) {
[_locationManager startMonitoringForRegion:geofence
desiredAccuracy:kCLLocationAccuracyBest];
}
}
- (NSArray*) buildGeofenceData {
NSString* plistPath = [[NSBundle mainBundle] pathForResource:#"regions" ofType:#"plist"];
_regionArray = [NSArray arrayWithContentsOfFile:plistPath];
NSMutableArray *geofences = [NSMutableArray array];
for(NSDictionary *regionDict in _regionArray) {
CLRegion *region = [self mapDictionaryToRegion:regionDict];
[geofences addObject:region];
}
return [NSArray arrayWithArray:geofences];
}
- (CLRegion*)mapDictionaryToRegion:(NSDictionary*)dictionary {
NSString *title = [dictionary valueForKey:#"title"];
CLLocationDegrees latitude = [[dictionary valueForKey:#"latitude"] doubleValue];
CLLocationDegrees longitude =[[dictionary valueForKey:#"longitude"] doubleValue];
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude, longitude);
//CLLocationDistance regionRadius = 50.000;
CLLocationDistance regionRadius = [[dictionary valueForKey:#"radius"] doubleValue]; //<--STOD DOUBLE ISTÄLLET
return [[CLRegion alloc] initCircularRegionWithCenter:centerCoordinate
radius:regionRadius
identifier:title];
}
- (void)initializeLocationUpdates {
[_locationManager startUpdatingLocation];
}
#pragma mark - Location Manager - Region Task Methods
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
NSLog(#"Entered Region - %#", region.identifier);
[self showRegionAlert:#"Entering Region" forRegion:region.identifier];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Exited Region - %#", region.identifier);
[self showRegionAlert:#"Exiting Region" forRegion:region.identifier];
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Started monitoring %# region", region.identifier);
}
#pragma mark - Location Manager - Standard Task Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
self.coordinateLabel.text = [NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude, newLocation.coordinate.longitude];
}
#pragma mark - Alert Methods
- (void) showRegionAlert:(NSString *)alertText forRegion:(NSString *)regionIdentifier {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:alertText
message:regionIdentifier
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
}
- (void)showAlertWithMessage:(NSString*)alertText {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Location Services Error"
message:alertText
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}
#end
Appdelegate.h
#import <UIKit/UIKit.h>
#class ViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ViewController *viewController;
#end
Appdelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
//DERAS ALLTSÅ KML!!
#synthesize window;
#synthesize viewController;
//
//Deras alltså KML!!
#pragma mark -
#pragma mark Application lifecycle
//
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
//Deras alltså KML!!
[window addSubview:viewController.view];
//
return YES;
}
//Deras alltså KML!!!
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
//
#end