自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

后臺(tái)定位上傳的代碼實(shí)踐

移動(dòng)開發(fā)
先來(lái)看看實(shí)現(xiàn)這個(gè)功能的具體需求是什么 由于我們是實(shí)時(shí)定位的生活類社交APP 所以我們需要做到一下幾點(diǎn)

[[142068]]

前言

之前的文章說(shuō)過(guò) 我現(xiàn)在做的是LBS定位的社交APP 其中主要的一個(gè)功能就是能夠?qū)崟r(shí)定位社交圈中各個(gè)成員的位置 后臺(tái)實(shí)時(shí)上傳位置則是非常重要的一個(gè)技術(shù)點(diǎn) 接下來(lái)就來(lái)說(shuō)說(shuō)我關(guān)于這方面的實(shí)踐經(jīng)驗(yàn)

需求

先來(lái)看看實(shí)現(xiàn)這個(gè)功能的具體需求是什么 由于我們是實(shí)時(shí)定位的生活類社交APP 所以我們需要做到一下幾點(diǎn)

1. 如果用戶的位置在持續(xù)變化 則隔一段時(shí)間上報(bào)一次

由于我們希望能夠?qū)崟r(shí)的將用戶的位置變化反饋在APP里 所以定時(shí)的上報(bào)是剛需

2. 如果用戶的移動(dòng)速度很慢 則隔一段距離上報(bào)一次

如果用戶是低速率的狀態(tài)(比如步行的移動(dòng)速度大概就是1m/s左右) 這個(gè)時(shí)候如果還按(1)中的方式來(lái)上報(bào)的話 由于變化太小 地圖上的點(diǎn)會(huì)非常的密集 這種數(shù)據(jù)的意義不大(而且如果要做軌跡服務(wù)的話 這些密集點(diǎn)都是必須有花掉的) 所以這時(shí)候我們按照距離間隔來(lái)上報(bào)

3. 如果用戶的位置在到達(dá)某處后沒(méi)有變化 則不繼續(xù)上報(bào)

我們只關(guān)心位置的變化 如果用戶的位置沒(méi)有變化或者變化很小 其實(shí)是不需要上報(bào)其位置的(比如進(jìn)入的公司 或者等一個(gè)很長(zhǎng)時(shí)間的紅燈) 這時(shí)候我們就不上報(bào)(以達(dá)到省電的目的)

4. 切換到后臺(tái)也要能定位上報(bào)

后臺(tái)上報(bào)是必須的 用戶不可能一直運(yùn)行著我們的APP (iOS4開始就支持了)

5. APP因各種原因終止運(yùn)行后(用戶主動(dòng)關(guān)閉, 系統(tǒng)殺掉) 也要能定位上報(bào)

用戶主動(dòng)關(guān)閉APP的幾率不大 但是因系統(tǒng)調(diào)度被殺掉的情況是很普遍的 這個(gè)時(shí)候我們也要能夠上報(bào) (iOS7開始已支持被殺掉后喚醒)

分析完需求 接下來(lái)就開始介紹如何實(shí)現(xiàn)

準(zhǔn)備

首先做一些準(zhǔn)備工作

在target的Capabilities選項(xiàng)中打開Background Modes 并勾選Location updates

 

然后在plist中添加NSLocationAlawaysUsageDescription的鍵 在value中隨便鍵入任何內(nèi)容

完成這兩步 我們的前期工作就完成了 Background Modes是iOS7帶入的新功能 而NSLocationAlawaysUsageDescription為了增強(qiáng)權(quán)限機(jī)制引入的提示描述 不添加這個(gè)的話 定位功能可是使用不了的

代碼

定位肯定要跟CLLocationManager打交道 所以我們先定義一個(gè)CLLocationManager的子類 并根據(jù)需求中的幾點(diǎn)定義三個(gè)變量

  1. @interface MMLocationManager : CLLocationManager 
  2. + (instancetype)sharedManager; 
  3. @property (nonatomic, assign) CGFloat minSpeed; //最小速度 
  4. @property (nonatomic, assign) CGFloat minFilter; //最小范圍 
  5. @property (nonatomic, assign) CGFloat minInteval; //更新間隔 
  6. @end 

這里解釋一下這幾個(gè)參數(shù)

minSpeed 如果當(dāng)前運(yùn)動(dòng)速度大于此值 則滿足需求(1) 以時(shí)間為更新依據(jù)(minFilter) 如果當(dāng)前運(yùn)動(dòng)速度小于此值 則滿足需求(2) 以范圍為更新依據(jù)(minInteval)

minFilter 最小的觸發(fā)范圍 用于需求(1)

minInteval 更新間隔 用于需求(2)

接下來(lái)是初始化函數(shù)

  1. - (instancetype)init 
  2. self = [super init]; 
  3. if ( self ) 
  4. self.minSpeed = 3
  5. self.minFilter = 50
  6. self.minInteval = 10
  7. self.delegate = self; 
  8. self.distanceFilter = self.minFilter; 
  9. self.desiredAccuracy = kCLLocationAccuracyBest; 
  10. return self; 

這里的默認(rèn)值可以根據(jù)需求來(lái)調(diào)整

然后是位置更新后的處理邏輯 其實(shí)也非常的簡(jiǎn)單

  1. - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
  2. CLLocation *location = locations[0]; 
  3. NSLog(@"%@",location); 
  4. //根據(jù)實(shí)際情況來(lái)調(diào)整觸發(fā)范圍 
  5. [self adjustDistanceFilter:location]; 
  6. //上傳數(shù)據(jù) 
  7. [self uploadLocation:location]; 

而這個(gè)adjustDistanceFilter函數(shù) 就是整個(gè)代碼的核心 會(huì)根據(jù)當(dāng)前速度來(lái)動(dòng)態(tài)的調(diào)整distanceFilter這個(gè)參數(shù) 以滿足我們的需求
 

  1. /** 
  2. * 規(guī)則: 如果速度小于minSpeed m/s 則把觸發(fā)范圍設(shè)定為50m 
  3. * 否則將觸發(fā)范圍設(shè)定為minSpeed*minInteval 
  4. * 此時(shí)若速度變化超過(guò)10% 則更新當(dāng)前的觸發(fā)范圍(這里限制是因?yàn)椴荒懿煌5脑O(shè)置distanceFilter, 
  5. * 否則uploadLocation會(huì)不停被觸發(fā)) 
  6. */ 
  7. - (void)adjustDistanceFilter:(CLLocation*)location 
  8. // NSLog(@"adjust:%f",location.speed); 
  9.  
  10. if ( location.speed < self.minSpeed ) 
  11. if ( fabs(self.distanceFilter-self.minFilter) > 0.1f ) 
  12. self.distanceFilter = self.minFilter; 
  13. else 
  14. CGFloat lastSpeed = self.distanceFilter/self.minInteval; 
  15.  
  16. if ( (fabs(lastSpeed-location.speed)/lastSpeed > 0.1f) || (lastSpeed < 0) ) 
  17. CGFloat newSpeed = (int)(location.speed+0.5f); 
  18. CGFloat newFilter = newSpeed*self.minInteval; 
  19.  
  20. self.distanceFilter = newFilter; 

這里要注意到的是distanceFilter這個(gè)參數(shù)不能一直進(jìn)行設(shè)置 因?yàn)槊看卧O(shè)置完以后 再接下來(lái)的一秒以后 會(huì)立即觸發(fā)didUpdateLocations回調(diào)(系統(tǒng)的標(biāo)準(zhǔn)最短更新間隔是1秒 即更新頻率為1hz) 所以這里只有當(dāng)變化超過(guò)10%的時(shí)候才會(huì)重置distanceFilter

接下來(lái) 為了能夠正確的在被殺掉的情況下被喚醒 我們還要做***一步操作 在AppDelegate的didFinishLaunchingWithOptions中加入下面的代碼

  1. if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) { 
  2.  
  3. if ( [[MMLocationManager sharedManager] respondsToSelector:@selector(requestAlwaysAuthorization)] ) 
  4. [[MMLocationManager sharedManager] requestAlwaysAuthorization]; 
  5. //這是iOS9中針對(duì)后臺(tái)定位推出的新屬性 不設(shè)置的話 可是會(huì)出現(xiàn)頂部藍(lán)條的哦(類似熱點(diǎn)連接) 
  6. if ( [self respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) 
  7. [MMLocationManager sharedManager].allowsBackgroundLocationUpdates = YES; 
  8. [[MMLocationManager sharedManager] startUpdatingLocation]; 

這是因?yàn)楸粴⒌舻腁PP 在后臺(tái)被系統(tǒng)喚醒時(shí) launchOptions會(huì)包含UIApplicationLaunchOptionsLocationKey**字段來(lái)進(jìn)行標(biāo)識(shí) 這時(shí)我們?cè)僦匦聠?dòng)定位功能即可

至此 滿足我們需求的定位功能就完成了 為此我寫了一個(gè)demo來(lái)驗(yàn)證(使用模擬器 然后選擇Debug->Location->Freeway Drive) 結(jié)果如下

 

 

接下來(lái)我們會(huì)討論一下相關(guān)的幾個(gè)問(wèn)題

討論

為什么不用定時(shí)器來(lái)控制定位間隔

網(wǎng)上有很多教程是用NSTimer來(lái)實(shí)現(xiàn)的 但是其實(shí)這樣不是很好 雖然定位的間隔是固定的 但是耗電的問(wèn)題無(wú)法解決 后臺(tái)會(huì)持續(xù)的更新定位 無(wú)論當(dāng)前的位置是否在更新 當(dāng)然 如果你的使用場(chǎng)景就是要每隔一段時(shí)間來(lái)上傳 就可以使用定時(shí)器來(lái)處理

使用distanceFilter來(lái)處理 會(huì)有些什么問(wèn)題

由于distanceFilter=currentSpeed*minInteval 那么間隔的時(shí)間因?yàn)樗俣鹊淖兓鴷?huì)有波動(dòng) 但是這個(gè)波動(dòng)是在可接受范圍的 如果速度加快或者變慢 那么下一次的更新時(shí)間則會(huì)相應(yīng)的縮短或者變長(zhǎng) 但是因?yàn)槲覀兪窃谡鎸?shí)生活環(huán)境中 速度的變化不可能那么快 所以這個(gè)誤差是可以接受的 另外我們對(duì)distanceFilter針對(duì)速度進(jìn)行矯正 因而總體來(lái)說(shuō) 間隔還是會(huì)保持在我們與其的范圍內(nèi)的

為什么不使用allowDeferredLocationUpdatesUntilTraveled:timeout:

allowDeferredLocationUpdatesUntilTraveled是iOS6推出的一個(gè)新的API 看名字我們可以知道這個(gè)函數(shù)的作用是延遲位置更新 直到移動(dòng)了xx米或者時(shí)間超過(guò)了xx秒 那么這個(gè)函數(shù)不正好滿足了我們的所有要求么? 可是萬(wàn)萬(wàn)沒(méi)想到 事情并不是這樣的 這個(gè)函數(shù)并不好用

接下來(lái)是吐槽時(shí)間 ?(????)

為什么說(shuō)這個(gè)函數(shù)不好用呢? 首先 這個(gè)函數(shù)的要求很多 我們來(lái)看看要這個(gè)函數(shù)起作用要滿足哪些條件

必須iPhone5以及之后的硬件設(shè)備才支持

desiredAccuracy必須設(shè)置為kCLLocationAccuracyBest或者kCLLocationAccuracyBestForNavigation

distanceFilter必須設(shè)置為kCLDistanceFilterNone

只在APP運(yùn)行在后臺(tái)時(shí)生效 前臺(tái)運(yùn)行時(shí)是不會(huì)進(jìn)行延遲處理的

只有系統(tǒng)在低功耗(Low Power State)的時(shí)候才有可能生效

關(guān)于Low Power State在iOS中的描述 我只在蘋果官網(wǎng)的文檔中找到部分定義

iOS is very good at getting a device into a low power state when it’s not being used. At idle, very little power is drawn and energy impact is low. When tasks are actively occurring, system resources are being used and those resources require energy. However, sporadic tasks can cause the device to enter an intermediate state—neither idle nor active—when the device isn’t doing anything. There may not be enough time during these intermediate states for the device to reach absolute idle before the next task executes. When this occurs, energy is wasted and the user’s battery drains faster.

據(jù)我簡(jiǎn)單的了解 這個(gè)**Low Power State”只有在黑屏的狀態(tài)下(不只是鎖屏)才有可能觸發(fā) 只要有任何電量屏幕的操作(就連推送也算) 都會(huì)使APP退出這個(gè)狀態(tài) 同時(shí) 如果在充電狀態(tài)下 也是無(wú)法進(jìn)入的

我嘗試在真機(jī)和模擬器上使用這個(gè)API 但結(jié)果APP還是以1HZ的頻率在定位(設(shè)置了kCLDistanceFilterNone的原因)

雖然locationManager:didFinishDeferredUpdatesWithError:在指定的時(shí)間后成功的回調(diào)了 但是結(jié)果還是沒(méi)有deffer 于是我查了一下 原來(lái)這個(gè)函數(shù)無(wú)法直接進(jìn)行調(diào)試的 因?yàn)?

不支持模擬器 deferredLocationUpdatesAvailable用于檢測(cè)設(shè)備是否支持 模擬器會(huì)返回NO

不支持真機(jī)調(diào)試 因?yàn)檎{(diào)試時(shí)Xcode會(huì)阻止程序休眠 導(dǎo)致程序無(wú)法進(jìn)入低功耗狀態(tài)

結(jié)論就是…這個(gè)東西連調(diào)試都沒(méi)辦法 所以我也沒(méi)有那么多時(shí)間跑到外面去測(cè)試這個(gè)東西… 況且使用我上述的方法已經(jīng)基本可以滿足需求… 所以我已放棄繼續(xù)研究這個(gè)API了 因?yàn)榫退闶褂昧诉@個(gè)東西 也僅僅是錦上添花而已

如果有哪些同學(xué)知道如何正確的使用這個(gè)東西 請(qǐng)留言告訴我 萬(wàn)分感謝!

小結(jié)

文中的demo可以在這里找到 另外demo中用到了Realm來(lái)存儲(chǔ)數(shù)據(jù)(模擬上傳操作) 有興趣的同學(xué)可以看一下

責(zé)任編輯:chenqingxiang 來(lái)源: 里脊串的開發(fā)隨筆
相關(guān)推薦

2015-07-23 10:09:45

后臺(tái)定位代碼

2023-11-06 09:56:10

研究代碼

2012-09-29 10:09:19

網(wǎng)站架構(gòu)后臺(tái)構(gòu)建架構(gòu)

2023-01-05 07:54:49

vivo故障定位

2018-01-16 16:32:12

架構(gòu)前臺(tái)后臺(tái)

2022-05-24 16:14:01

CSS實(shí)踐

2015-06-24 10:06:09

iOS 9適配后臺(tái)

2014-10-29 13:52:38

程序員

2020-03-09 14:10:48

代碼開發(fā)工具

2023-04-28 08:06:04

低代碼AI智能

2021-09-08 09:37:54

工具代碼Python

2015-09-23 10:14:48

iOS 代碼實(shí)踐

2012-08-09 09:10:56

代碼審查代碼

2017-05-12 09:24:21

Python代碼Logger

2020-05-25 11:14:59

代碼程序開發(fā)

2015-01-29 09:52:43

Swift 開源蘋果

2018-05-10 15:06:43

Java Web分層實(shí)踐

2015-08-13 09:39:41

2018-01-12 14:37:34

Java代碼實(shí)踐

2009-07-02 13:59:35

JSP后臺(tái)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)