CLLocationManager works with ARC? - objective-c

All I'm trying to do is get the current position of the User, and show on the map of my app, so I am using CLLocationManager class, as anybody can see below:
ViewController.h
import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface MeuPrimeiroViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>{
IBOutlet MKMapView *mapView;
}
#property(nonatomic, retain) CLLocationManager *locationManager;
#end
ViewController.m
-(void)viewDidAppear:(BOOL)animated{
//Lendo as coordenadas com o core location
if ([CLLocationManager locationServicesEnabled]) {
NSLog(#"CLLocationManager locationServicesEnabled == ON");
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
}else{
NSLog(#"CLLocationManager locationServicesEnabled == OFF");
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
CLLocationDistance altitude = newLocation.altitude;
CLLocationDegrees latitude = newLocation.coordinate.latitude;
CLLocationDegrees longitude = newLocation.coordinate.longitude;
NSLog(#"Altitude, Latitude, Longitude: %f, %f, %f",altitude,latitude,longitude);
MKCoordinateRegion coordenada = {{0.0,0.0}, {0.0,0.0}};
coordenada.center.latitude = latitude;
coordenada.center.longitude = longitude;
[mapView setRegion:coordenada animated:YES];
//Calculando distancias
CLLocationDistance distancia = [newLocation distanceFromLocation:oldLocation];
NSLog(#"Distancia em metros : %f",distancia);
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"Error: %#",[error description]);
}
The problem with this code is that my methods of CLLocationManager class not being called, I did some research on the internet over a possible problem related to the ARC, but none of them worked, any suggestions?

iOS 8 changed 2 things that make this not work as it did before
On iOS 8, you need to call requestWhenInUseAuthorization or requestAlwaysAuthorization before calling startUpdatingLocation
You MUST provide a location usage description corresponding to what type of authorization you are requesting in the Info.plist (either NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription). You should also continue to provide the value for the old pre-iOS 8 key (NSLocationUsageDescription) as a fallback for older versions of iOS.

All I'm trying to do is get the current position of the User, and show on the map of my app
You do not need any of that in order to put the user's location on a map. Just tell the map to track the user's location. In iOS 8 you do need user authorization to do this, and for that you do need a location manager. But these two lines of code are sufficient (this is Swift but I'm sure you can translate):
self.locman.requestWhenInUseAuthorization()
self.map.userTrackingMode = .Follow

Related

CLLocationManager startMonitoringSignificantLocationChanges doesn't work

I want my application to get location updates even if it's terminated I tried to sign up for location changes using SignificantLocationChanges but I seems that I'm not getting any updates.
In my AppDelegate.m I have the following setup:
#interface AppDelegate () <RCTBridgeDelegate, CLLocationManagerDelegate>
#property (nonatomic, strong) UMModuleRegistryAdapter *moduleRegistryAdapter;
#property (nonatomic, strong) CLLocationManager* locationManager;
#property BOOL didShowLocationUpdateNotification;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
/// other setup
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
switch(status) {
case kCLAuthorizationStatusNotDetermined:
NSLog(#"locationManagerDidChangeAuthorization - kCLAuthorizationStatusNotDetermined");
break;
case kCLAuthorizationStatusRestricted:
NSLog(#"locationManagerDidChangeAuthorization - kCLAuthorizationStatusRestricted");
break;
case kCLAuthorizationStatusDenied:
NSLog(#"locationManagerDidChangeAuthorization - kCLAuthorizationStatusDenied");
break;
case kCLAuthorizationStatusAuthorizedAlways:
[self.locationManager setAllowsBackgroundLocationUpdates:YES];
[self.locationManager startUpdatingLocation];
[self.locationManager startMonitoringSignificantLocationChanges];
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
NSLog(#"locationManagerDidChangeAuthorization - kCLAuthorizationStatusAuthorizedWhenInUse");
break;
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
NSLog(#"didUpdateLocation");
NSLog(#"Locations %#", locations);
}
I have the following Background Modes enabled:
I also have those keys in my info.plist:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Your location is required to track your journeys. By selecting ALWAYS your journeys will record automatically.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Your location is required to track your journeys. </string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location is required to track your journeys. WARNING: Journeys will not automatically record with 'When In Use' selected</string>
And yet, after I terminate the app, it never wakes up again even though I changed my location drastically.
What else am I mussing here?
I'm testing it on iPhone 11 with iOS 15.

Using CLLocationManager on iOS Simulator to find latitude and longitude [duplicate]

This question already has answers here:
Location Services not working in iOS 8
(26 answers)
Closed 8 years ago.
I am trying to create an application that opens with a map using MKMapView, and then by creating a delegate to CLLocationManger find the current location of the user.
I have posted my code below. The problem that I am having right now is that that although the map does appear when opening the this the simulator it does not give a position or a new heading from the NSLog that should be passing the latitude and longitude.
I am new to Objective - C and App Development, does anyone see if I am missing some of the protocol for CLLocationManger? Thanks for all your help.
Sorry the code is a little sloppy, pasted it in quickly.
#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#property (nonatomic,strong)CLLocationManager * myLocationManger;
#property (nonatomic,strong) IBOutlet MKMapView *myMapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"insdie view did load");
// Setting the map to be big as the view
self.myMapView =[[MKMapView alloc]init];
//Initial Property to Map
self.myMapView =[[MKMapView alloc] init];
//Set type to Standard
self.myMapView.mapType = MKMapTypeStandard;
//Set Mask for AutoReszing
self.myMapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
//Add the View!
[self.view addSubview:self.myMapView];
///*Now lets Use my CLLocation Manager to Locate the iPhone's Posistion*////
//Chekcs if Location Services are Enabled
if ([CLLocationManager locationServicesEnabled]) {
self.myLocationManger = [[CLLocationManager alloc] init];
self.myLocationManger.delegate = self;
[self.myLocationManger startUpdatingLocation];
}
else{
//Location Services are available we will need software to ask to turn this On
//The user is SOL if they refuse to turn on Location Services
NSLog(#"Location Services not enabled");
}
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
//This method will show us that we recieved the new location
NSLog(#"Latitude = %f",newLocation.coordinate.latitude );
NSLog(#"Longitude =%f",newLocation.coordinate.longitude);
}
-(void)locationManager:(CLLocationManager *)manager
didFinishDeferredUpdatesWithError:(NSError *)error{
NSLog(#"Error with Updating");
}
-(void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
//Failed to recieve user's location
NSLog(#"failed to recived user's locatio");
}
I found that in the new iOS 8, you need two keys added to the Plist. This article explains the process beautifuly.
http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/

Why does UILocalNotification with region not fire?

I have followed the example given in the WWDC 2014 session "What's New in iOS Notifications" to set up a UILocalNotification delivery when a region's boundary is crossed.
However, my notification never fires on device nor simulator running iOS beta 3. The notification works fine when I tested using a fireDate instead of a region (not both at same time-- that's not allowed).
I have set NSLocationWhenInUseUsageDescription in my Info.plist.
Here is my Obj-C code:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) CLLocation *notifLocation;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// test points at Apple HQ
self.notifLocation = [[CLLocation alloc] initWithLatitude:37.331741 longitude:-122.030333];
[self setupLocationMonitoring];
}
- (void) setupLocationMonitoring
{
if (self.locationManager == nil) {
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 10; // meters
// iOS 8+ request authorization to track the user’s location
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
}
- (void)registerLocationNotification
{
UILocalNotification *locNotification = [[UILocalNotification alloc] init];
locNotification.alertBody = #"Hello!";
// doesn't work
locNotification.regionTriggersOnce = NO;
locNotification.region = [[CLCircularRegion alloc] initWithCenter:self.notifLocation.coordinate radius:50 identifier:#"PlaceName"];
// works:
// locNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
UIApplication *application = [UIApplication sharedApplication];
[application cancelAllLocalNotifications];
[application scheduleLocalNotification:locNotification];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
// check status to see if we’re authorized
BOOL canUseLocationNotifications = (status == kCLAuthorizationStatusAuthorizedWhenInUse);
if (canUseLocationNotifications) {
[self registerLocationNotification];
}
}
#end
Note: this question is about iOS 8's new Location Notifications, not about region monitoring on older versions of iOS.
Your code works fine for me. Here are the steps on iPhone Simulator:
1) Open Simulator app and choose the following option from the top menu Debug -> Location -> Custom Location and put there the coordinates as you have in code: (37.331741, -122.030333)
2) Run your Xcode project on iPhone Simulator
3) Background the app
4) Open the same top menu item Debug -> Location but change it from Custom Location to Freeway Drive or City Run. Play with City Run/ Freeway Drive and Custom Location
I see the notification when I follow these steps. Looks like it doesn't work in case appropriate coordinate is a starting one but it works when the coordinate changes to appropriate from some others.

Annotation with canShowCallout switch viewController

I have a problem. I search with google apis to places and let me create a annotation pin on the map. The data is stored in a dict. I try THESE position to transfer with a callout including the data to another ViewController.
Here are Parts of my code:
.h file:
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "MapPoint.h"
#define kGOOGLE_API_KEY #"MyGoogleAPIsKey"
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#interface FirstViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
CLLocationCoordinate2D currentCentre;
BOOL firstLaunch;
int currenDist;
}
- (IBAction)myButton:(UIBarButtonItem *)sender;
- (IBAction)myPosition:(UIBarButtonItem *)sender;
#property (strong, nonatomic) IBOutlet MKMapView *mapView;
#end
.m file:
#implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//Make this controller the delegate for the map view.
self.mapView.delegate = self;
// Ensure that you can view your own location in the map view.
[self.mapView setShowsUserLocation:YES];
//Instantiate a location object.
locationManager = [[CLLocationManager alloc] init];
//Make this controller the delegate for the location manager.
[locationManager setDelegate:self];
//Set some parameters for the location object.
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
firstLaunch=YES;
[_mapView setCenterCoordinate:_mapView.userLocation.coordinate];
}
-(void)plotPositions:(NSArray *)data {
// 1 - Remove any existing custom annotations but not the user location blue dot.
for (id<MKAnnotation> annotation in _mapView.annotations)
{
if ([annotation isKindOfClass:[MapPoint class]])
{
[_mapView removeAnnotation:annotation];
}
}
// 2 - Loop through the array of places returned from the Google API.
for (int i=0; i<[data count]; i++)
{
//Retrieve the NSDictionary object in each index of the array.
NSDictionary* place = [data objectAtIndex:i];
// 3 - There is a specific NSDictionary object that gives us the location info.
NSDictionary *geo = [place objectForKey:#"geometry"];
// Get the lat and long for the location.
NSDictionary *loc = [geo objectForKey:#"location"];
// 4 - Get your name and address info for adding to a pin.
NSString *name = [place objectForKey:#"name"];
NSString *vicinity = [place objectForKey:#"vicinity"];
// 4.5 - Get id for detailed view.
NSString *myId = [place objectForKey:#"id"];
// Create a special variable to hold this coordinate info.
CLLocationCoordinate2D placeCoord;
// Set the lat and long.
placeCoord.latitude=[[loc objectForKey:#"lat"] doubleValue];
placeCoord.longitude=[[loc objectForKey:#"lng"] doubleValue];
// 5 - Create a new annotation.
MapPoint *placeObject = [[MapPoint alloc] initWithName:name address:vicinity coordinate:placeCoord];
[_mapView addAnnotation:placeObject];
NSLog(#"%#", myId);
}
}
-(void)button:(id)sender
{
//here is my main problem ...
}
if i done a misstake or something else tell me that please.
I am grateful for any answer!
okay forget to say I am really new to Obj-C so every tip is usefull for me!
Regards Curtis
As #Anna Karenina said, you can implement the accessory view delegate BUT you must remember to put a UIControl or this method will not be called. Otherwise that view needs to handle its own touch events.
from the documentation:
If the view you specify is also a descendant of the UIControl class,
you can use the map view’s delegate to receive notifications when your
control is tapped. If it does not descend from UIControl, your view is
responsible for handling any touch events within its bounds.
reference

No visible #interface for 'CLLocation' declares the selector 'setDesiredAccuracy:'

I added the CoreLocation framework, and I keep rereading the code in my book to make sure I copied it down correctly but I am getting a persistent No visible #interface for 'CLLocation' declares the selector 'setDesiredAccuracy:' error.
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface WhereamiViewController : UIViewController {
CLLocation *locationManager;
}
#end
#import "WhereamiViewController.h"
#interface WhereamiViewController ()
#end
#implementation WhereamiViewController
-(id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
locationManager = [[CLLocation alloc] init
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
return self;
}
#end
You want CLLocationManager, not CLLocation.
I think you wanted to use CLLocationManager ...
CLLocationManager *locationManager;
Only CLLocationManager declares a selector named -setDesiredAccuracy, not CLLocation.
CLLocation
is a location object, it holds a specific coordinate/location, that can be displayed on a map view. However, CLLocationManager is an object which manages location and heading updates. setDesiredAccuracy is the method where you set the accuracy of the location manager's location and heading updates. If you set the accuracy high, the location manager will update with a very accurate point of where you are, but considerably slow. (Not really, but when you compare to other accuracies).
The delegate method where the location updates it:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
To start the updates, you can first customize it like you said, with the accuracy and distance filter. Then to start, simply write:
[locationManager startUpdatingLocation];
And, so I can guess how you would stop updates.
NOTE: If you are on ARC, make your location manager an instance variable (declared in .h) because it releases the location manager very quickly and the popup to let the user decide if your app can track you location will popup and then disappear in less than a second. And of course your locations wont update.