I've been having trouble figuring out why startRangingBeaconsInRegion is never called. I know for certain the startMonitoringForRegion is called, and I tried outputting the mRegionsArray as a string and it worked. But the didEnterRegion is not being called however. And I tried walking around back and forth trying to get a signal from my beacons (ie, entering the region), but no luck. I can't wrap my head around what might be wrong, went through a lot of questions on here and none of them mirrored my issue.
I have a Beacons table view and each cell is supposed to contain information (major, minor) on each beacon. Except, these cells aren't being filled because the ranging is not happening. :( I even tried to change it so it only detects one beacon. I know the problem doesn't lie within the Beacon class I created because the loadTestData() function works...
If anyone can help, it would be much appreciated.
BeaconTableViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface BeaconTableViewController : UITableViewController <CLLocationManagerDelegate>
#property (strong, nonatomic) CLBeaconRegion *beaconRegion;
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
BeaconTableViewController.m
#import "BeaconTableViewController.h"
#import "Beacon.h"
#import "BeaconTableViewCell.h"
#interface BeaconTableViewController () <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *beaconsTableView;
#property (strong, nonatomic) NSMutableArray *beacons;
#end
#implementation BeaconTableViewController
- (void)loadTestData {
self.beacons = [[NSMutableArray alloc] init];
Beacon *beacon1 = [[Beacon alloc] init];
beacon1.major = [[NSNumber alloc] initWithInt:21311];
beacon1.minor = [[NSNumber alloc] initWithInt:21331];
[self.beacons addObject:beacon1];
Beacon *beacon2 = [[Beacon alloc] init];
beacon2.major = [[NSNumber alloc] initWithInt:10011];
beacon2.minor = [[NSNumber alloc] initWithInt:10012];
[self.beacons addObject:beacon2];
Beacon *beacon3 = [[Beacon alloc] init];
beacon3.major = [[NSNumber alloc] initWithInt:65535];
beacon3.minor = [[NSNumber alloc] initWithInt:30136];
[self.beacons addObject:beacon3];
[self.beaconsTableView beginUpdates];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:self.beacons.count-1 inSection:0];
[self.beaconsTableView insertRowsAtIndexPaths:#[newIndexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.beaconsTableView endUpdates];
}
- (void)initRegion {
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:#"AB Region"];
[self.locationManager startMonitoringForRegion:self.beaconRegion];
}
- (void) locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
UIAlertView *alertMonitoring = [[UIAlertView alloc] initWithTitle:#"User Notification"
message:#"Started monitoring for region."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertMonitoring show];
NSSet *mRegions = [self.locationManager monitoredRegions];
NSArray *mRegionsArray = [mRegions allObjects];
NSString *str = [mRegionsArray componentsJoinedByString:#","];
UIAlertView *alertRegion = [[UIAlertView alloc] initWithTitle:#"User Notification"
message:str
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertRegion show];
}
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
UIAlertView *alertRanging = [[UIAlertView alloc] initWithTitle:#"User Notification"
message:#"Started ranging."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertRanging show];
CLBeacon *foundBeacon = [beacons firstObject];
Beacon *beacon;
beacon.major = foundBeacon.major;
beacon.minor = foundBeacon.minor;
UIAlertView *alertBeaconFound = [[UIAlertView alloc] initWithTitle:#"User Notification"
message:[[[#"Major: " stringByAppendingString:[NSString stringWithFormat:#"%#", beacon.major]] stringByAppendingString:#", Minor: "] stringByAppendingString:[NSString stringWithFormat:#"%#", beacon.minor]]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertBeaconFound show];
[self.beacons addObject:beacon];
[self.beaconsTableView beginUpdates];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:self.beacons.count-1 inSection:1];
[self.beaconsTableView insertRowsAtIndexPaths:#[newIndexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.beaconsTableView endUpdates];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"User Notification"
message:#"Did enter region."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}
- (void)viewDidLoad {
[super viewDidLoad];
// [self loadTestData];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self initRegion];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.beacons count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BeaconTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"BeaconCell" forIndexPath:indexPath];
Beacon *beacon = [self.beacons objectAtIndex:indexPath.row];
cell.beacon = beacon;
return cell;
}
Under iOS 8, Apple added some new requirements to using the location manager (And iBeacons are a Location Manager function)
You have to add the keys NSLocationAlwaysUsageDescription and/or NSLocationWhenInUseUsageDescription to your info.plist file, and then before trying to start monitoring beacons you have to check the authorization status and if it is kCLAuthorizationStatusNotDetermined, you have to make a new call, either requestAlwaysAuthorization or requestWhenInUseAuthorization
The code might look something like this:
CLAuthorizationStatus status =[CLLocationManager authorizationStatus];
if (status ==kCLAuthorizationStatusDenied)
{
NSLog(#"Location manager denied");
}
theLocManager = [[CLLocationManager alloc] init];
theLocManager.delegate = self;
if (status == kCLAuthorizationStatusNotDetermined
&& [theLocManager respondsToSelector: #selector(requestAlwaysAuthorization)])
[theLocManager requestAlwaysAuthorization];
(You have to add the check to make sure the location manage responds to the requestAlwaysAuthorization or requestWhenInUseAuthorization method, since they are only available in iOS >= 8.)
The thing I don't like about this OS change is that if you don't make the request call, your calls to start monitoring beacons fail silently.
Related
I have a problem with the refresh information on your GPS position.
The function given by me "locationManager" when you click the button does not refresh the information in the "Label".
My code: http://pastebin.com/hWeq6gTS
I am a novice programmer iOS. Please help.
The issue that is not always obvious with the location services is that you have to have one of these two keys in your Info.plist:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
Then, when starting updating of your position, don't forget to request permissions first (again, depending on your requirements (when in use/always):
[self.locationManager requestWhenInUseAuthorization]
[self.locationManager requestAlwaysAuthorization]
Add these two properties in info.plist
'NSLocationAlwaysUsageDescription' and below property
Create CocoaTouch Class 'LocationManager' inherit from NSObject like below class.
Singleton Location Manager Class .h
#import <Foundation/Foundation.h>
#interface LocationManager : NSObject <CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
}
#property (strong, nonatomic) NSString *longitude;
#property (strong, nonatomic) NSString *latitude;
#property (strong, nonatomic) CLLocation *currentLocation;
+ (instancetype)sharedInstance;
#end
Implementation here .m
#import "LocationManager.h"
#implementation LocationManager
- (id) init
{
self = [super init];
if (self != nil)
{
[self locationManager];
}
return self;
}
+ (instancetype)sharedInstance
{
static LocationManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[LocationManager alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
- (void) locationManager
{
if ([CLLocationManager locationServicesEnabled])
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLDistanceFilterNone;
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
else{
UIAlertView *servicesDisabledAlert = [[UIAlertView alloc] initWithTitle:#"Location Services Disabled" message:#"You currently have all location services for this device disabled. If you proceed, you will be showing past informations. To enable, Settings->Location->location services->on" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:#"Continue",nil];
[servicesDisabledAlert show];
[servicesDisabledAlert setDelegate:self];
}
}
- (void)requestWhenInUseAuthorization
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// If the status is denied or only granted for when in use, display an alert
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusDenied) {
NSString *title;
title = (status == kCLAuthorizationStatusDenied) ? #"Location services are off" : #"Background location is not enabled";
NSString *message = #"To use background location you must turn on 'Always' in the Location Services Settings";
UIAlertView *alertViews = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Settings", nil];
[alertViews show];
}
// The user has not enabled any location services. Request background authorization.
else if (status == kCLAuthorizationStatusNotDetermined) {
[locationManager requestWhenInUseAuthorization];
}
}
#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 didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
case kCLAuthorizationStatusNotDetermined:
case kCLAuthorizationStatusRestricted:
case kCLAuthorizationStatusDenied:
{
// do some error handling
}
break;
default:{
[locationManager startUpdatingLocation];
}
break;
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *location;
location = [manager location];
CLLocationCoordinate2D coordinate = [location coordinate];
_currentLocation = [[CLLocation alloc] init];
_currentLocation = newLocation;
_longitude = [NSString stringWithFormat:#"%f",coordinate.longitude];
_latitude = [NSString stringWithFormat:#"%f",coordinate.latitude];
// globalObjects.longitude = [NSString stringWithFormat:#"%f",coordinate.longitude];
// globalObjects.latitude = [NSString stringWithFormat:#"%f",coordinate.latitude];
}
#end
import
#import "LocationManager.h"
in your AppDelegate.h
and call that in your AppDelegate.m's like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[LocationManager sharedInstance];
return true;
}
Then just get
[LocationManager sharedInstance].longitude or latitude for updated lat long.
Instead of using
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
// Location update code
}
use this function to get updated location
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
// Assigning the last object as the current location of the device
CLLocation *currentLocation = [locations lastObject];
}
Sometimes we do face problem when we do not check the authorisation status. You can check this code
// Custom initialization code
CLLocationManager *manager = [[CLLocationManager alloc]init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
// Setting distance fiter to 10 to get notified only after location change about 10 meter
manager.distanceFilter = kCLDistanceFilterNone;
// Requesting for authorization
if ([manager respondsToSelector:#selector(requestWhenInUseAuthorization)]){
[manager requestWhenInUseAuthorization];
}
// Immediately starts updating the location
[manager startUpdatingLocation];
[manager startUpdatingHeading];
if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
// user activated automatic attraction info mode
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusDenied ||
status == kCLAuthorizationStatusAuthorizedWhenInUse ||
status == kCLAuthorizationStatusNotDetermined) {
// present an alert indicating location authorization required
// and offer to take the user to Settings for the app via
// UIApplication -openUrl: and UIApplicationOpenSettingsURLString
[manager requestAlwaysAuthorization];
}
[manager requestWhenInUseAuthorization];
else
[manager requestAlwaysAuthorization];
endif
Hi i have below code which works fine on iPod touch 5, but same code is not working on iPhone 6, i done research on same issue but i have not found anything useful. both devices have latest iOS.
Both devices have iOS 8
// MapViewController.m
// SidebarDemo
//
// Created by Simon on 30/6/13.
// Copyright (c) 2013 Appcoda. All rights reserved.
//
#import "PetFinderViewController.h"
#import "SWRevealViewController.h"
#interface PetFinderViewController ()
#end
#implementation PetFinderViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed:(51/255.0) green:(51/255.0) blue:(51/255.0) alpha:1] ;
self.title = #"Pet Finder";
// Change button color
//_sidebarButton.tintColor = [UIColor colorWithWhite:0.96f alpha:0.2f];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
// Check if beacon monitoring is available for this device
if (![CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Monitoring not available" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil]; [alert show]; return;
}
else
{
// Initialize location manager and set ourselves as the delegate
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Create a NSUUID
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"ebefd083-70a2-47c8-9837-e7b5634df524"];
// Setup a new region AND start monitoring
str_beaconIdentifier = #"in.appstute.marketing";
self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:1 minor:1 identifier:str_beaconIdentifier];
self.myBeaconRegion.notifyEntryStateOnDisplay = YES;
self.myBeaconRegion.notifyOnEntry = YES;
self.myBeaconRegion.notifyOnExit = YES;
[self.locationManager startMonitoringForRegion:self.myBeaconRegion];
self.lbl_rangeStatus.text = #"Finding Your Pet";
self.lbl_regionStatus.text = #"";
self.lbl_distance.text = #"";
}
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (![CLLocationManager locationServicesEnabled]) {
NSLog(#"Couldn't turn on ranging: Location services are not enabled.");
}
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
NSLog(#"Couldn't turn on monitoring: Location services not authorised.");
[self.locationManager requestAlwaysAuthorization];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Core Location Delegate methods
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region
{
UILocalNotification *notify = [[UILocalNotification alloc] init];
notify.alertBody = #"You are near your Pet's region.";
notify.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notify];
// We entered a region, now start looking for our target beacons!
//self.statusLabel.text = #"Finding beacons.";
self.lbl_rangeStatus.text = #"Pet Found";
self.lbl_regionStatus.text = #"Status : Entered Region";
[self.locationManager startRangingBeaconsInRegion:self.myBeaconRegion];
//Opening camera
/*if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.allowsEditing = YES;
//[self presentModalViewController:imagePicker animated:YES];
[self presentViewController:imagePicker animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Camera Unavailable"
message:#"Unable to find a camera on your device."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alert show];
alert = nil;
}*/
}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion *)region
{
UILocalNotification *notify = [[UILocalNotification alloc] init];
notify.alertBody = #"You are far away from your Pet's region.";
notify.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notify];
// Exited the region
//self.statusLabel.text = #"None found.";
self.lbl_rangeStatus.text = #"Pet Not Found";
self.lbl_regionStatus.text = #"Status : Exited Region";
[self.locationManager stopRangingBeaconsInRegion:self.myBeaconRegion];
}
-(void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region
{
CLBeacon *foundBeacon = [beacons firstObject];
// Retrieve the beacon data from its properties
NSString *uuid = foundBeacon.proximityUUID.UUIDString;
NSString *major = [NSString stringWithFormat:#"%#", foundBeacon.major];
NSString *minor = [NSString stringWithFormat:#"%#", foundBeacon.minor];
NSLog(#"uuid=%#, major=%#, minor=%#",uuid, major, minor);
self.lbl_regionStatus.text = #"Status : Entered Region";
if(foundBeacon.proximity==CLProximityImmediate)
{
NSLog(#"Immediate");
//self.Lb_proxomity.text = #"Immediate";
}
else if (foundBeacon.proximity==CLProximityNear)
{
NSLog(#"Near");
//self.Lb_proxomity.text = #"Near";
}
else if(foundBeacon.proximity==CLProximityFar)
{
NSLog(#"Far");
//self.Lb_proxomity.text = #"Far";
}
else if(foundBeacon.proximity==CLProximityUnknown)
{
NSLog(#"Unknown");
//self.Lb_proxomity.text = #"Unknown";
}
float actualDistance = foundBeacon.accuracy/10;
NSLog(#"Distance = %f",actualDistance);
if(actualDistance >= 0.0)
{
self.lbl_distance.text = [NSString stringWithFormat:#"Distance : %.2f m",actualDistance];
}
//self.Lb_meter.text = [NSString stringWithFormat:#"%.2f",foundBeacon.accuracy];
//self.Lb_centimeter.text = [NSString stringWithFormat:#"%.2f",(foundBeacon.accuracy*100)];
//[self presentExhibitInfoWithMajorValue:foundBeacon.major.integerValue];
//Calling this method to display strength for distance between user and the pet
[self fn_showStrengthForDistanceBetweenUserAndPet:actualDistance];
}
#pragma mark - Check Background App Refresh status
-(BOOL)CanDeviceSupportAppBackgroundRefresh
{
// Override point for customization after application launch.
if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusAvailable) {
NSLog(#"Background updates are available for the app.");
return YES;
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied)
{
NSLog(#"The user explicitly disabled background behavior for this app or for the whole system.");
return NO;
}else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted)
{
NSLog(#"Background updates are unavailable and the user cannot enable them again. For example, this status can occur when parental controls are in effect for the current user.");
return NO;
}
return NO;
}
#pragma mark - Check if monitoring region failed
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
NSLog(#"monitoringDidFailForRegion - error: %#", [error localizedDescription]);
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLBeaconRegion *)region{
if (state == CLRegionStateInside) {
//Start Ranging
[manager startRangingBeaconsInRegion:region];
}
else{
//Stop Ranging
[manager stopRangingBeaconsInRegion:region];
}
}
#end
I suspect you are having authorization issues on your iPhone. Set a breakpoint or add NSLog statements to make sure this line is getting called:
[self.locationManager requestAlwaysAuthorization];
Do you get prompted? If not, uninstall and reinstall.
Also, check in setting that Bluetooth and Location services are enabled on the phone, and check settings on your app to see that location services are actually enabled for it.
You need to set one of
NSLocationAlwaysUsageDescription
or
NSLocationWhenInUseUsageDescription when requesting location updates (even with iBeacons).
If you don't, in iOS 8, this will fail silently.
I am very new to objective C and Xcode. I was trying to find out the location of my iphone simulator and went through a tutorial on youtube. Following is the code.
#import "MainClassViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface MainClassViewController () <CLLocationManagerDelegate>
#end
#implementation MainClassViewController
{
CLLocationManager *manager;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
manager = [[CLLocationManager alloc]init];
}
- (IBAction)LocationButton:(id)sender
{
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation];
}
#pragma mark CLLocationManagerDelegate Methods
- (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 didUpdateLocations:(CLLocation *)newLocation fromLocation: (CLLocation *) oldLocation {
NSLog(#"Location: %#", newLocation);
CLLocation *currentLocation = newLocation;
if(currentLocation != nil){
_Lattitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
_Longitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
}
}
#end
#import <UIKit/UIKit.h>
#interface MainClassViewController : UIViewController
- (IBAction)LocationButton:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *Lattitude;
#property (weak, nonatomic) IBOutlet UILabel *Longitude;
#end
My questions are:
1. I am not sure why labels are not getting updated with location.
2. I want to learn more about debugging. Any suitable resources available. Please keep in mind I do not want learn all about debugging. Only what is required for the basics.
I've followed online tutorials from AppCoda and Devfright to create an iBeacon detection app. I'm using an iBeacon from estimote, an iPad 3 with iOS 8. The app simply does not detect my iBeacon whereas its being detected by other iBeacon apps. I can't understand what I'm missing or doing wrong in my code.
Here's my .h file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate>
#property (nonatomic, strong) CLBeaconRegion *beaconRegion;
#property (nonatomic, strong) CLLocationManager *locManager;
#property (nonatomic, strong) IBOutlet UILabel *label1;
#property (nonatomic, strong) IBOutlet UILabel *label2;
#end
Here's my .m file:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locManager = [[CLLocationManager alloc] init];
self.locManager.delegate = self;
//default uuid for estimote beacons
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:#"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
self.beaconRegion = [[CLBeaconRegion alloc]initWithProximityUUID:uuid identifier:#"com.rk.testregion"];
[self.locManager startMonitoringForRegion:self.beaconRegion];
[self locationManager:self.locManager didStartMonitoringForRegion:self.beaconRegion];
// Check if beacon monitoring is available for this device
if (![CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Monitoring not available" message:nil delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil]; [alert show]; return;
}
}
-(void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region
{
// Beacon found!
self.label1.text = #"Welcome to";
self.label2.text = #"Location 1";
CLBeacon *foundBeacon = [beacons firstObject];
// retrieve the beacon data from its properties
NSString *uuid = foundBeacon.proximityUUID.UUIDString;
NSString *major = [NSString stringWithFormat:#"%#", foundBeacon.major];
NSString *minor = [NSString stringWithFormat:#"%#", foundBeacon.minor];
NSLog(#"UUID: %#", uuid);
NSLog(#"major: %#", major);
NSLog(#"minor: %#", minor);
}
- (void)viewDidDisappear:(BOOL)animated
{
[self.locManager stopRangingBeaconsInRegion:self.beaconRegion];
[super viewDidDisappear:animated];
}
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region
{
[self.locManager startRangingBeaconsInRegion:self.beaconRegion];
}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region
{
[self.locManager stopRangingBeaconsInRegion:self.beaconRegion];
self.label1.text = #"Searching again...";
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locManager startRangingBeaconsInRegion:self.beaconRegion];
}
#end
The delegate method didRangeBeacons simply does not get called. Could someone please let me know how to fix this.
Check out the answer below, which describes some extra hoops you now need to jump through to get this working:
Location Services not working in iOS 8
Full disclosure: I have not tried this myself.
I cannot resolve this issue and I have no idea why my UITableView duplicates rows whenever I click on the segment control. I want to refresh the table view with new data when segment control changes. I have tried many things and googled it but could not find any solution. I would appreciated if someone can help me please. I am still learning xcode and a lot to learn. here is my code -
#import "citsViewController.h"
#import "citsParseOperation.h"
#import "citsFuelFinder.h"
#import "citsTableViewCell.h"
#import "citsAboutViewController.h"
#import "MBProgressHUD.h"
#import <CoreLocation/CoreLocation.h>
// this framework is imported so we can use the kCFURLErrorNotConnectedToInternet error code
#import <CFNetwork/CFNetwork.h>
#import <MapKit/MapKit.h>
#interface citsViewController ()
{
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
NSString *currentLoc;
int productName;
}
#property (nonatomic) NSMutableArray *earthquakeList;
#property (nonatomic) citsFuelFinder *currentEarthquakeObject;
#property (nonatomic, weak) IBOutlet UILabel *locationLabel;
// queue that manages our NSOperation for parsing earthquake data
#property (nonatomic) NSOperationQueue *parseQueue;
#end
#pragma mark -
#implementation citsViewController
#synthesize nomatchesView;
#synthesize footerLabel;
#synthesize headerLabel;
#synthesize fuelType;
#synthesize bannerIsVisible;
- (void)viewDidLoad {
[super viewDidLoad];
//refresh the tableview
UIRefreshControl *refreshControl=[[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
self.refreshControl=refreshControl;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[infoButton addTarget:self action:#selector(aboutUs:) forControlEvents:UIControlEventTouchUpInside];
//add info button in the navigation controller
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton] ;
//initialize location manager
locationManager=[[CLLocationManager alloc] init];
//to get location
geocoder=[[CLGeocoder alloc] init];
//show network activity
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
//call the location manager update function
[locationManager startUpdatingLocation];
}
-(void)refresh:(id)sender {
//update table data
[locationManager startUpdatingLocation];
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
- (void)dealloc {
// we are no longer interested in these notifications:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kAddEarthquakesNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kEarthquakesErrorNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSCurrentLocaleDidChangeNotification
object:nil];
}
/**
Handle errors in the download by showing an alert to the user. This is a very simple way of handling the error, partly because this application does not have any offline functionality for the user. Most real applications should handle the error in a less obtrusive way and provide offline functionality to the user.
*/
- (void)handleError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
NSString *alertTitle = NSLocalizedString(#"Error", #"Title for alert displayed when download or parse error occurs.");
NSString *okTitle = NSLocalizedString(#"OK ", #"OK Title for alert displayed when download or parse error occurs.");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle message:errorMessage delegate:nil cancelButtonTitle:okTitle otherButtonTitles:nil];
[alertView show];
}
/**
Our NSNotification callback from the running NSOperation to add the earthquakes
*/
- (void)addEarthquakes:(NSNotification *)notif {
assert([NSThread isMainThread]);
[self addEarthquakesToList:[[notif userInfo] valueForKey:kEarthquakeResultsKey]];
}
/**
Our NSNotification callback from the running NSOperation when a parsing error has occurred
*/
- (void)earthquakesError:(NSNotification *)notif {
assert([NSThread isMainThread]);
[self handleError:[[notif userInfo] valueForKey:kEarthquakesMessageErrorKey]];
}
/**
The NSOperation "ParseOperation" calls addEarthquakes: via NSNotification, on the main thread which in turn calls this method, with batches of parsed objects. The batch size is set via the kSizeOfFuelPumpBatch constant.
*/
- (void)addEarthquakesToList:(NSArray *)earthquakes {
NSInteger startingRow = [self.earthquakeList count];
NSInteger earthquakeCount = [earthquakes count];
NSMutableArray *indexPaths = [[NSMutableArray alloc] initWithCapacity:earthquakeCount];
for (NSInteger row = startingRow; row < (startingRow+earthquakeCount); row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
[indexPaths addObject:indexPath];
}
NSLog(#"record count %d",earthquakeCount);
[self.earthquakeList addObjectsFromArray:earthquakes];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
//[self.tableView reloadData];
}
#pragma mark - UITableViewDelegate
// The number of rows is equal to the number of earthquakes in the array.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.earthquakeList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kEarthquakeCellID = #"EarthquakeCellID";
citsTableViewCell *cell = (citsTableViewCell *)[tableView dequeueReusableCellWithIdentifier:kEarthquakeCellID];
if(cell==nil)
{
cell=[[citsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kEarthquakeCellID];
}
// Get the specific earthquake for this row.
citsFuelFinder *earthquake = (self.earthquakeList)[indexPath.row];
[cell configureWithEarthquake:earthquake];
return cell;
}
/**
* When the user taps a row in the table, display the USGS web page that displays details of the earthquake they selected.
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *buttonTitle = NSLocalizedString(#"Cancel", #"Cancel");
//NSString *buttonTitle1 = NSLocalizedString(#"Show USGS Site in Safari", #"Show USGS Site in Safari");
NSString *buttonTitle2 = NSLocalizedString(#"Show Location in Maps", #"Show Location in Maps");
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:buttonTitle destructiveButtonTitle:nil
otherButtonTitles: buttonTitle2, nil];
[sheet showInView:self.view];
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, 500)];
headerLabel=[[UILabel alloc] initWithFrame:CGRectMake(10, 1.0, 300, 25)];
headerLabel.numberOfLines=0;
fuelType=[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"ULP", #"PULP",#"Diesel",#"LPG", nil]];
fuelType.frame = CGRectMake(10, 30, 300,25);
//set first segment selected
[fuelType setSelectedSegmentIndex:0];
[fuelType addTarget:self action:#selector(segmentedControlHasChangedValue) forControlEvents:UIControlEventValueChanged];
headerLabel.font=[UIFont systemFontOfSize:10.0];
[headerView insertSubview:fuelType aboveSubview:headerLabel];
[headerView addSubview:headerLabel];
[headerView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"footer.gif"]]];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60;
}
#pragma mark -
/**
* Called when the user selects an option in the sheet. The sheet will automatically be dismissed.
*/
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
citsFuelFinder *earthquake = (citsFuelFinder *)(self.earthquakeList)[selectedIndexPath.row];
switch (buttonIndex) {
case 0: {
// open the earthquake info in Maps
// create a map region pointing to the earthquake location
CLLocationCoordinate2D location = (CLLocationCoordinate2D) { earthquake.latitude, earthquake.longitude };
NSValue *locationValue = [NSValue valueWithMKCoordinate:location];
MKCoordinateSpan span = (MKCoordinateSpan) { 2.0, 2.0 };
NSValue *spanValue = [NSValue valueWithMKCoordinateSpan:span];
NSDictionary *launchOptions = #{ MKLaunchOptionsMapTypeKey : #(MKMapTypeStandard),
MKLaunchOptionsMapCenterKey : locationValue,
MKLaunchOptionsMapSpanKey : spanValue,
MKLaunchOptionsShowsTrafficKey : #(NO),
MKLaunchOptionsDirectionsModeDriving : #(NO) };
// make sure the map item has a pin placed on it with the title as the earthquake location
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:location addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:earthquake.location];
[mapItem openInMapsWithLaunchOptions:launchOptions];
break;
}
}
[self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES];
}
- (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
{
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
// Regiser for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
HUD.labelText = #"Loading";
HUD.detailsLabelText = #"updating data";
HUD.square = YES;
self.earthquakeList = [NSMutableArray array];
self.currentEarthquakeObject=nil;
if([self.earthquakeList count] >0)
{
[self.earthquakeList removeAllObjects];
[self.tableView reloadData];
}
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(addEarthquakesToList:) onTarget:self withObject:nil animated:YES];
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSString *latitude=[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
NSString *longitude=[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
citsTableViewCell *tcell = [[citsTableViewCell alloc] init];
//set the latitude and longitude
tcell.lon =[longitude doubleValue];
tcell.lat = [latitude doubleValue];
NSLog(#"Lat:%#, Lon:%#", latitude,latitude);
}
//stop updating location
[locationManager stopUpdatingLocation];
//reverse geocoding
NSLog(#"Resolving the address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
currentLoc=[NSString stringWithFormat:#"%#",placemark.locality];
if(currentLoc == NULL)
{
currentLoc=#"N/A";
}
NSLog(#"%#",currentLoc);
//add text to headertext
NSDate *currDate=[NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yy HH:mm:ss"];
NSString *dateString=[dateFormatter stringFromDate:currDate];
NSString *loc=[NSString stringWithFormat:#"Your location: %#, Updated on: %#", currentLoc, dateString ];
[dateFormatter setDateFormat:#"EEEE, dd/MM/yyyy"];
NSString *headerDate=[dateFormatter stringFromDate:currDate];
headerLabel.text=[NSString stringWithFormat:#"Prices for: %#\n%#", headerDate,loc];
//currentLoc=[NSString stringWithFormat:#"%#", placemark.locality];
currentLoc=#"Mirrabooka";
if(productName==0)
{
productName=1;
}
NSString *prdStr=[[NSString alloc] initWithFormat:#"%d", productName];
NSString *str =[currentLoc stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSString *feedURLString =[[NSString alloc] initWithFormat: #"http://www.fuelwatch.wa.gov.au/fuelwatch/fuelWatchRSS?Product=%#&Suburb=%#", prdStr,str ];
NSURLRequest *earthquakeURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]];
NSLog(#"%#",feedURLString);
// send the async request (note that the completion block will be called on the main thread)
//
// note: using the block-based "sendAsynchronousRequest" is preferred, and useful for
// small data transfers that are likely to succeed. If you doing large data transfers,
// consider using the NSURLConnectionDelegate-based APIs.
//
[NSURLConnection sendAsynchronousRequest:earthquakeURLRequest queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// back on the main thread, check for errors, if no errors start the parsing
//
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// here we check for any returned NSError from the server, "and" we also check for any http response errors
if (error != nil) {
[self handleError:error];
}
else {
// check for any response errors
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ((([httpResponse statusCode]/100) == 2) ) {
// Update the UI and start parsing the data,
// Spawn an NSOperation to parse the earthquake data so that the UI is not
// blocked while the application parses the XML data.
//
citsParseOperation *parseOperation = [[citsParseOperation alloc] initWithData:data];
[self.parseQueue addOperation:parseOperation];
}
else {
NSString *errorString =
NSLocalizedString(#"HTTP Error", #"Error message displayed when receving a connection error.");
NSDictionary *userInfo = #{NSLocalizedDescriptionKey : errorString};
NSError *reportError = [NSError errorWithDomain:#"HTTP"
code:[httpResponse statusCode]
userInfo:userInfo];
[self handleError:reportError];
}
}
}];
// Start the status bar network activity indicator.
// We'll turn it off when the connection finishes or experiences an error.
//
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.parseQueue = [NSOperationQueue new];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(addEarthquakes:)
name:kAddEarthquakesNotificationName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(earthquakesError:)
name:kEarthquakesErrorNotificationName object:nil];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
NSLog(#"%d",[self.earthquakeList count]);
}
-(void)clearData{
[self.tableView beginUpdates];
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (int i = [self.tableView numberOfRowsInSection:0] - 1; i >= 0; i--)
{
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:0]];
NSLog(#"Deleted: %d",i);
}
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationFade];
[self.earthquakeList removeAllObjects];
[self.tableView endUpdates];
//[self.tableView reloadData] ;
}
-(void)segmentedControlHasChangedValue{
int product;
product=fuelType.selectedSegmentIndex;
switch (product) {
case 0:
productName=1;
[locationManager startUpdatingLocation];
[self clearData];
break;
case 1:
productName=2;
[self clearData];
[locationManager startUpdatingLocation];
break;
case 2:
productName=4;
[self clearData];
[locationManager startUpdatingLocation];
break;
case 3:
prod![enter image description here][1]uctName=5;
[self clearData];
[locationManager startUpdatingLocation];
break;
}
NSLog(#"%d",productName);
return;
}
#end
Try removing all previous object from the self.earthquakeList before adding new 1. use [self.earthquakeList removeAllObjects]
Remove this Line,
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
And uncomment,
[self.tableView reloadData];
You are Already updating the data set, So you just need to reload the tableView instead of explicitly insert row.