5

rhomobile フレームワークを使用して iPhone のコンパスを機能させようとしています。私はすでにrhomobileの部分を行い、iPhoneでネイティブメソッドを呼び出す作業ラッパーを作成しましたが、イベントを機能させることができません。

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

iOS 5.1 を搭載した iphone 4 でコードを実行しています。コンソールに init のデバッグ メッセージが表示されますが、didUpdateHeading デリゲートのデバッグ メッセージは表示されません。誰かが私がここで見逃した手がかりを得ましたか?

アップデート

コードを機能させるには、バックグラウンド スレッドでコードを実行する必要があると思います。現在、locationmanager_init は初期化 + コードを残すため、アクティブではなく、イベントは発生しません。これをバックグラウンドで初期化してアクティブに保つ簡単な解決策はありますか?

更新 2

IDを返し、使用self = [super init]しましたが、まだ修正されていません:(

GitHub コード locationmanager_init で初期化し、locationmanager_get_heading でデータを取得します

4

3 に答える 3

14

CLLocationManagerメイン スレッドで初期化する必要があります。この SO をここで確認するか、アクティブな実行ループを持つスレッドから実行する必要があります。この SO をここで確認してください。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.

あなたlocationControllerとそのCCLocationManager内部が初期化後に生きていることを確認してください。ここをチェックしてください。私はここで間違っているかもしれませんが、あなたの Github コードから*lc、自動解放プールで変数が解放されているようです。リテインを追加してみてください。

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

これがあなたの問題の原因だと思います。オブジェクトが解放された場合、更新は取得されません。

質問とは関係ありませんが、

最後に呼び出す必要があります[super dealloc]が、最初に呼び出す必要はありません。このSOをここで確認してください

init メソッドの return ステートメントは、最後から 2 番目の括弧の前ではなく、最後の括弧の前に置きます。

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

        }
    }
    return self;
}
于 2012-09-12T19:43:49.000 に答える
0

おそらくこれは全体的な問題の解決策ではありませんが、initメソッドにreturnステートメントがありません。

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

  return self;
}
于 2012-09-10T09:24:42.020 に答える
0
- (void)locationManager:(CLLocationManager *)manager 
didUpdateHeading:(CLHeading *)heading;
- (void)locationManager:(CLLocationManager *)manager 
didFailWithError:(NSError *)error;

これらはデリゲート メソッドではなく、インスタンス メソッドです。

https://developer.apple.com/library/mac/#documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.htmlを確認し てください

于 2012-08-31T15:27:07.757 に答える