2

現在の位置に基づいてローカルデータをチェックし、アプリを閉じ、少し移動して、アプリを再度開くときに、didUpdateToLocationの失敗を克服しようとしています。何が起こるかというと、ユーザーはある場所に行き、リストをチェックし、別の場所に行き、リストは更新されますが、古い位置データを使用します。

新しい新しい場所があることを確認したいと思います。

このコードの何が問題になっていますか?

double aa,bb,cc;

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    [manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
        //old data? retry.
    aa=[newLocation.timestamp timeIntervalSinceReferenceDate];
    bb=[NSDate timeIntervalSinceReferenceDate];
    cc=bb-aa;   //must be <60 - minute-fresh
    if (cc>60) {
        [manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
        [manager startUpdatingLocation];    //only stop if new reliable pos fetched.
        return;
    }
...handle position
}

症状は、アプリの起動時にccが約1200秒であり、再試行するたびに数秒増加することです。

私は試しましたが-[newLocation.timestamp timeIntervalSinceNow]、同様に、再試行するたびに数秒増加します。ある時点では、間隔は約2400でした。

影響を受ける可能性がある場合は、FilterNoneとAccuracyBestを使用しています。

私は、あなたが新しい立場にいることを確認するために、代替のコードソリューションを受け入れています。

4

3 に答える 3

2

答えは、あなたがそれが振る舞うように処理を書く必要があるということでした。

私はこの一般的な問題について読みました。「力」とは、電話に最適な条件下で信頼できる位置を与える明確な動作を開始することを意味することを明確にすべきでした。忙しくない-満足するまで待つか、すぐに結果/エラーコードを期待します。

常識的な観点から、すべての開発者が望むのは、少なくともパラメータ内の位置を要求し、それが有効で正確な範囲内であるか、キャンセルされた場合、またはタイムアウトした場合にのみコールバックする追加のメソッドです。条件によってそれが妨げられる場合は、カスタムコードで処理できるようにするために、難解な動作をテストする必要はありません。

これについて質問する必要があった理由は次のとおりです。

  1. 上記のように機能するメソッドは存在しません

  2. 本のコードを使用する(その他のiPhone 3開発)

  3. それを最初から書くとき(LocateMe.xprojを見て)、それを発見します:

  4. シミュレーターの動作は電話の動作とは異なります(位置自体については話しません。これは明らかにIPルックアップで可能な限り優れていますが、didUpdateToLocationの動作です)。シミュレータの制限を認識して、メソッドは少なくともデバイスでの動作と同じように動作する必要があります。ただし、現在、正しく記述されたロケーション処理/チェックコードはシミュレーターでタイムアウトしますが(LocateMeの例のように)、誤ったコード(1回要求してコールバックでnewLocationを使用)は機能します。

  5. [locationManagerstopUpdatingLocation]の後にdidUpdateToLocationが2回呼び出される原因となるバグ。

これに加えて、(私のように)自分の位置に基づいてデータをロードし、そのデータがアプリケーションの複数のビューで必要な場合、Appleのロケーションフェッチメソッドの動作では、更新のチェーンを簡単に処理できません- load-calculate-アプリ全体で一貫して問題なく表示されます。特に、ユーザー/上司の認識や、それがどのように機能するか(岩)とシステムがどのように機能するか(難しい場所)の決定の間に行き詰まっている場合。

これが、デバイスとシミュレーターで動作する私の現在のコードです。

//ask for a position, as fresh as possible.
-(void)updateMeMap {
    lastloc.coordinate=homeloc.coordinate;
    lm.delegate=self;
    ctr=0;
    [self performSelector:@selector(stopUpd) withObject:nil afterDelay:gpstimeout];
    [lm startUpdatingLocation];
}

//called on each position update.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    ctr++;
    if (ctr<15) {
        NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
        NSLog(@"%d",ctr);
        if (locationAge<60) {
            NSLog(@"Found");
            ctr=40;
            homeloc.coordinate=newLocation.coordinate;
            [self stopUpd];
            [self reload];
        } else {
            NSLog(@"Lastupd");
            lastloc.coordinate=newLocation.coordinate;
        }
    } else {
            //enough tries, if not canceled choose lastloc.
        if (ctr<40) {
            NSLog(@"Last");
            ctr=40;
            homeloc.coordinate=lastloc.coordinate;  
            [self stopUpd];
            [self reload];
        }
    }
}

//force stop updates. ctr prevents extra calls after stopUpdatingLocation.
//called after the timeout delay, if position found, cancel the timeout.
-(void)stopUpd {
    [lm stopUpdatingLocation];
    lm.delegate=nil;
    if (ctr<15) {
        ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
        NSLog(@"Timeout");
        homeloc.coordinate=lastloc.coordinate;  //@need "copy"?
        [self reload];
    } else {
        ctr=40; //2 extra calls after stopupda... otherwise, now do nothing.
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stopUpd) object:nil];
    }
}

    // "couldn't get userlocation" handler. I also cancel like this on connectionDidFailWithError.
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"Location failed: %@",[error localizedDescription]);
    ctr=0;
    [self stopUpd];
}

ctrが2つの余分な呼び出しを防ぐためにある場合、lastlocは最後に認識された信頼できる位置であり、homelocは、[セルフリロード]を使用した場所固有のデータの(スレッド化された)ロードに使用される電話の位置です。

定数15および60は、実際のテストからの安全な値です。gpstimeoutは30に設定されています。シミュレーターで多くの作業を行う場合は、3秒などの短い値に設定することをお勧めします。これは、古いが比較的使用可能な位置であり、タイムアウトになるまではそれ以上ないためです。

編集:あなたが私のコードを最もよくするか、省略を指摘することができるなら、私はそれを答えとしてマークします、私は自分自身を答えとしてマークするのが嫌いです。

于 2011-08-18T11:25:33.277 に答える
1

以前のアプリの1つで同様の問題が発生しました。

私に関する限り、場所の更新を強制する方法はありません-(私は長い間検索しましたが、何も見つかりませんでした)

私が見つけた1つのことUIBackgroundModesは、info.plistのキーを使用していることでした。

一部のタイプのバックグラウンド実行のサポートは、それらを使用するアプリケーションによって事前に宣言する必要があります。アプリケーションは、Info.plistファイルにUIBackgroundModesキーを含めることにより、このサポートを宣言します。その値は、次の値を持つ1つ以上の文字列を含む配列です。

  • オーディオ。アプリケーションは、バックグラウンドでユーザーに音声コンテンツを再生します。(これには、AirPlayを使用したオーディオまたはビデオコンテンツのストリーミングが含まれます。)
  • location。このアプリケーションは、バックグラウンドで実行しているときでも、ユーザーに自分の場所を通知し続けます。
  • VoIP。このアプリケーションは、ユーザーがインターネット接続を使用して電話をかける機能を提供します。

それがあなたが探しているものです。詳細については、ドキュメントを参照してください。

于 2011-08-16T12:59:52.803 に答える
1

次のように、より多くのコードを年齢チェックに含めるとどうなりますか。

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
    if (locationAge<60) {
        [manager stopUpdatingLocation]; //only stop if new reliable pos fetched.
     ...handle position
    }
}
于 2011-08-16T13:43:55.677 に答える