2012-08-31 7 views
5

Sto cercando di far funzionare la bussola dell'iPhone utilizzando il framework rhomobile. Ho già creato la parte rhomobile, ho creato un wrapper funzionante che chiama i metodi nativi sull'iPhone, ma non riesco a far funzionare gli eventi.I delegati di CLLocationManager non funzionano dopo l'inizializzazione

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; 
} 

sto correndo il codice su un iPhone 4 con iOS 5.1, nella console posso vedere i messaggi di debug di init, ma non vedo mai un messaggio di debug del delegato didUpdateHeading. Qualcuno ha idea di cosa mi sia perso qui?

UPDATE

Penso di aver bisogno di eseguire il mio codice in un thread in background per farlo funzionare. Attualmente il locationmanager_init inizializza + lascia il codice, quindi non è attivo e gli eventi non vengono attivati. Chiunque ha una soluzione semplice inizializzando questo in background per mantenerlo attivo?

UPDATE 2

restituito l'id, utilizzato self = [super init] ed ancora alcuna correzione :(

GitHub code Inizializza con locationmanager_init, recupera i dati con locationmanager_get_heading

+0

Dai un'occhiata alla https://developer.apple.com/library/mac/#documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.html – fibnochi

+0

ho provato con e senza definire i delegati nel .h file. Utilizzato anche UIViewController invece di NSObject, come è stato fatto nell'esempio Teslameter di Apple, ancora nessun progresso :( – Vikko

+0

inviami il tuo codice email – fibnochi

risposta

13

Devi init il CLLocationManager sul thread principale, selezionare questa SO here, o eseguirlo da un thread con un loop corsa attiva, controllare questo SO here, dalla documentazione di Apple:

Configuration of your location manager object must always occur on a thread with 
an active run loop, such as your application’s main thread. 

Assicurati che il tuo locationController e il CCLocationManager al suo interno siano attivi dopo l'inizializzazione, controlla here. Potrei sbagliarti qui, ma dal tuo codice Github, sembra che la variabile *lc venga rilasciata nel pool di autorelease. Prova a dargli una riserva in più.

lc = [[[locationController alloc] init] retain]; 

Immagino che questa sia la causa del tuo problema. Se l'oggetto viene rilasciato non si otterranno aggiornamenti.

non inerenti alla domanda, ma:

si dovrebbe chiamare [super dealloc] ultimo, ma non prima, controllare questo SO here

Mettere l'istruzione return nel metodo init prima dell'ultima parentesi, e non prima della seconda ultimo.

 ... 
     // start the compass 
     [locationManager startUpdatingHeading]; 

     } 
    } 
    return self; 
} 
+0

Ho provato e aggiornato il codice su github. Nella console in xcode non vedo alcuna intestazione che appare, tuttavia ho avuto qualche errore che non ho visto prima: '13 settembre 13:00 : 44 sconosciuto CommCenter [56] : kDataAttachStatusNotification inviato, wasAttached: 1 isAttached: 1' – Vikko

+0

dopo aver combinato la risposta con 'performSelectorOnMainThread' ha funzionato !! Grazie per il vostro aiuto, sono rimasto bloccato su questo per circa 7 settimane:) Puoi immaginare quanto sono felice di poter continuare il mio sviluppo ora. Codice di lavoro aggiornato @ github – Vikko

+0

Ho avuto il problema di trovarsi su un altro thread. Ho paura di pensare a quanto tempo mi sarebbe voluto capire senza la tua risposta, quindi grazie mille! – poshaughnessy

0
- (void)locationManager:(CLLocationManager *)manager 
didUpdateHeading:(CLHeading *)heading; 
- (void)locationManager:(CLLocationManager *)manager 
didFailWithError:(NSError *)error; 

Questi sono i vostri metodi di istanza metodi non delegati

controllo https://developer.apple.com/library/mac/#documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.html

+3

La domanda è per iOS (che ha un metodo delegato didUpdateHeading). Il tuo link punta alla documentazione di OS X. – Anna

0

Forse questa non è la soluzione al problema generale, ma il metodo di init manca l'istruzione return:

- (id)init { 
    if (self = [super init]) { 
    // do your setup here 
    } 

    return self; 
} 
+0

Ho giocato con molte forme di inizializzazione e ho dimenticato di rimetterlo: P Anche se non risolve nulla, dovrebbe essere lì, grazie per il report! – Vikko

+0

Penso anche che il problema sia con il tuo [init]. dai tuoi frammenti di codice, devi impostare in modo esplicito *** self = [super init] ***, poiché self non è ancora pronto, a meno che tu non lo faccia come suggerito da tilo, if (self = [super init]) {.. .}. in bocca al lupo! – dklt

+0

Ho provato questo e nessuna correzione, peccato :( – Vikko