2011-08-16 69 views
2

我試圖在檢查基於當前位置的本地數據時,didUpdateToLocation有時失敗,關閉應用程序,旅行一點,再次打開應用程序。會發生什麼是用戶訪問一個地方,檢查列表,去另一個地方,列表更新,但使用舊的位置數據。部隊位置更新

我想確保我有一個新的newLocation。

這段代碼有什麼問題?

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,如果這可能會影響它。

我接受其他代碼解決方案以確保您擁有全新的位置。

回答

2

答案是,你需要寫處理你想讓它的行爲方式。

我讀過這個共同的問題。我應該澄清,「強制」意味着開始明確的行爲,在手機的最佳條件下給出可靠的位置。不要忙 - 等到滿意或期待立即結果/錯誤代碼。

從常識的角度來看,所有開發人員都希望至少有一個額外的方法來簡單地詢問參數中的位置,並且只有在有效並且準確時,或者取消或者超時時纔回調。如果條件阻止了它,那麼您就不需要測試出深奧的行爲,以便能夠使用自定義代碼處理它。

爲什麼我需要問這個根本是:

  1. 不存在上述使用的代碼從一本書

  2. 所描述的方法運作(更多iPhone 3開發)

  3. 從頭開始寫(看LocateMe.xproj),發現:

  4. 模擬器behav ior不同於電話行爲(不是說位置本身,這顯然與ip查找可以做到的一樣好,而是didUpdateToLocation的行爲)。認識到模擬器的侷限性,該方法至少應該像在設備上那樣工作。但目前,正確編寫的位置處理/檢查代碼只是在模擬器中超時(如LocateMe示例中),而不正確的代碼(請求一次並在回調函數上使用newLocation)有效。

  5. 和導致didUpdateToLocation在[locationManager stopUpdatingLocation]後被調用兩次的錯誤;

如果你(像我)根據你的位置加載數據,並將數據通過你的應用程序的多個視圖所需除此之外,蘋果的位置取方法的行爲並不能使容易在整個應用程序中始終如一地處理更新加載計算的問題鏈。特別是如果你在用戶/老闆的感知或決定如何工作(一塊石頭)和系統如何工作(一個困難的地方)之間卡住了。

這裏是我當前的代碼在設備上,並在模擬器的工作原理:

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

其中點擊率,以防止有2個額外要求,lastloc是最後知道的可靠的定位,homeloc是手機位置用於[線程]加載位置特定數據[自加載]。

常數15和60是來自真實世界測試的安全值; gpstimeout設置爲30.如果您在模擬器中工作很多,您可能希望將其設置爲3秒之類的簡短內容,因爲您將獲得的所有內容都是陳舊但相對可用的位置,並且只有在超時之後才能使用。

編輯:如果你最好我的代碼或指出一個遺漏,我會標記爲答案,我討厭標記自己的答案。

+0

注意:儘管這是基於CLLocationManager的當前行爲的代碼,並且您應該知道行爲可能會發生變化,但它在數月內沒有錯誤報告,可以可靠地運行。所以現在這是我們所有應用程序的可信解決方案,我會將其標記爲答案。真正的答案當然是不可能強制更新位置,但是這個代碼是一個很好的替代品。 –

1

我在以前的某個應用程序中遇到類似的問題。

有沒有辦法強制位置更新就我而言 - (我搜索了半天,也沒發現什麼)

有一兩件事,我發現用在UIBackgroundModes關鍵我info.plist中。

支持某些類型的後臺執行必須由使用它們的應用程序預先聲明。應用程序通過在其Info.plist文件中包含UIBackgroundModes鍵來聲明此支持。它的值是包含一個或多個具有以下值的字符串的數組:

  • 音頻。應用程序在 背景中播放聲音內容給用戶。 (這包括使用AirPlay流式傳輸音頻或視頻內容。)
  • location。即使在後臺運行,應用程序也會通知用戶它們的位置在 之間。
  • voip。應用程序 爲用戶提供了使用互聯網連接撥打電話的功能。

這就是你要找的。有關更多信息,請參閱docs

+0

謝謝,我會問,如果這是一個可行的選擇。 –

+0

問題是,這是一個應用程序,每天使用幾次,相隔數小時。現在,當應用程序在兩者之間關閉時,它不會關閉,或者它不會成爲問題 - 我只是要求開始更新。但是如果我要在後臺連續檢查位置,應用程序會在幾小時或幾天內不必要地耗盡電池,而無需執行任何操作或顯示任何有用的內容;它永遠不會停止。所以,刷新應用程序簡歷。預期的行爲是獲得新的用戶位置並顯示本地數據。 –

+0

通常這是在一個城市,所以沒問題。除了在我敢於提交數據之前,我仍然必須盡我所能獲得新的有效位置。如果數據錯誤,用戶會感到困惑或報告錯誤或認爲應用程序是廢話。我意識到嘗試是我所能做的,並且在地圖上導航對用戶來說很熟悉;你只需稍等一下,看看點移動到正確的地方。對於一個列表或其他內容來說,它並不那麼明顯,所以我必須通過處理代碼來爭取「嘗試」行爲(和Apple bug)以獲得可接受的演示行爲;你不能像移動一個點那樣隨機/替換數據。 –

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