I am trying to get the compass of the iphone to work using the rhomobile framework.
I already did the rhomobile part, created a working wrapper that calls native methods on the iphone, but I cant manage to get the events to work.
Locationmanager.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface locationController : NSObject <CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
}
@property (strong, nonatomic) CLLocationManager *locationManager;
- (id)init;
- (void)dealloc;
@end
Locationmanager.m
#import "Locationmanager.h"
#include "ruby/ext/rho/rhoruby.h"
//store the values
double gx, gy, gz, gth;
//init location
locationController *lc;
@implementation locationController
@synthesize locationManager;
- (id)init {
if (self = [super init]) {
self.locationManager = [[CLLocationManager alloc] init];
NSLog(@"%@", [CLLocationManager headingAvailable]? @"\n\nHeading available!\n" : @"\n\nNo heading..\n");
NSLog(@"%@", [CLLocationManager locationServicesEnabled]? @"\n\nLocation available!\n" : @"\n\nNo location..\n");
// check if the hardware has a compass
if ([CLLocationManager headingAvailable] == NO) {
// No compass is available. This application cannot function without a compass,
// so a dialog will be displayed and no magnetic data will be measured.
locationManager = nil;
UIAlertView *noCompassAlert = [[UIAlertView alloc] initWithTitle:@"No Compass!" message:@"This device does not have the ability to measure magnetic fields." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[noCompassAlert show];
[noCompassAlert release];
NSLog(@"\n***** ERROR *****\n No compass found !!!");
} else {
// setup delegate callbacks
locationManager.delegate = self;
// heading service configuration
locationManager.headingFilter = kCLHeadingFilterNone;
// location service configuration
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
//start location services
[locationManager startUpdatingLocation];
// start the compass
[locationManager startUpdatingHeading];
}
return self;
}
}
- (void)dealloc {
[super dealloc];
// Stop the compass
[locationManager stopUpdatingHeading];
[locationManager release];
}
// This delegate method is invoked when the location manager has heading data.
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading {
NSLog(@"\n\n***** New magnetic heading *****\n %f\n", heading.magneticHeading);
NSLog(@"\n\n***** New true heading *****\n %f\n", heading.trueHeading);
gx = heading.x;
gy = heading.y;
gz = heading.z;
gth = heading.trueHeading;
}
// This delegate method is invoked when the location managed encounters an error condition.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if ([error code] == kCLErrorDenied) {
// This error indicates that the user has denied the application's request to use location services.
NSLog(@"\n ***** ERROR *****\n Location not allowed!");
[locationManager stopUpdatingHeading];
} else if ([error code] == kCLErrorHeadingFailure) {
NSLog(@"\n ***** ERROR *****\n Magnetic interference or something!");
}
}
@end
//ruby wrappers
void locationmanager_init(void) {
// make sure we can only start this method once
static bool started = false;
if(!started) {
// Initialize the Objective C accelerometer class.
lc = [[locationController alloc] init];
started = true;
}
}
void locationmanager_get_heading(double *x, double *y, double *z, double *th) {
NSLog(@"\n ***** DEBUGGER *****\n Getting heading x: %f, y: %f, z: %f, heading: %f", gx, gy, gz, gth);
*x = gx;
*y = gy;
*z = gz;
*th = gth;
}
I’m running the code on an iphone 4 with iOS 5.1, in the console I can see the debug messages of init, but I never see a debug message of the didUpdateHeading delegate. Anyone got a clue what I missed here?
UPDATE
I think I need to run my code in a background thread to get it working. Currently the locationmanager_init initializes + leaves the code, therefor its not active and the events are not fired.
Anyone got a simple solution initializing this in the background to keep it active?
UPDATE 2
Returned the id, used self = [super init] and still no fix 🙁
GitHub code
Initializes with locationmanager_init, retrieves data with locationmanager_get_heading
You have to init the
CLLocationManageron the main thread, check this SO here, or run it from a thread with an active run loop, check this SO here, From Apple documentation:Make sure your
locationControllerand theCCLocationManagerinside it are alive past initialization, check here. I may be wrong here, but from your Github code, it seems that the*lcvariable is getting released in the autorelease pool. Try giving it an extra retain.I guess this is the cause of your problem. If the object is released you wont get any updates.
Not related to the question but:
You should call
[super dealloc]last but not first, check this SO herePut the return statement in your init method before the last parenthesis, and not before the second last.