在應(yīng)用程序中使用基于位置的信息是讓用戶與周圍世界保持連接的一個好方法。但是,不正確或不必要的位置使用可能會阻止設(shè)備睡眠,保持位置硬件通電,耗盡用戶的電池,并造成不良的用戶體驗(yàn)。遵循最佳實(shí)踐,優(yōu)化位置服務(wù)的使用,以提高能效。
有關(guān)使用定位服務(wù)的詳細(xì)信息,請參見 Location and Maps Programming Guide
請求快速位置更新
如果您的應(yīng)用程序只需要快速修復(fù)用戶的位置,那么最好調(diào)用location manager對象的requestLocation方法,如清單14-1所示。這樣做會在請求完成后自動停止位置服務(wù),如果不在其他地方使用,則會讓位置硬件斷電。以這種方式請求的位置更新通過回調(diào)傳遞到locationManager:didUpdateLocations:delegate方法,您必須在應(yīng)用程序中實(shí)現(xiàn)該方法。
清單14-1正式請求單個位置更新
-(void)viewDidLoad {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
}
-(void)getQuickLocationUpdate {
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Request a location update
[self.locationManager requestLocation];
// Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Process the received location update
}
不使用位置服務(wù)時停止這些服務(wù)
除了提供轉(zhuǎn)彎方向的導(dǎo)航應(yīng)用程序外,大多數(shù)應(yīng)用程序不需要一直打開位置服務(wù)。只有在需要時才打開位置服務(wù)。然后,讓它們打開足夠長的時間,以便定位并再次關(guān)閉它們。除非用戶在移動的車輛中,否則當(dāng)前位置的更改頻率不應(yīng)太高而成為問題。如果需要其他更新,您可以稍后重新啟動位置服務(wù)。
要停止標(biāo)準(zhǔn)位置更新,請調(diào)用位置管理器對象的stopUpdatengLocation方法。見清單14-2。
清單14-2不再需要時停止位置更新
-(void)getLocationUpdate {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Start location updates
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Get a fix on the user's location
...
// Stop location updates
[self.locationManager stopUpdatingLocation];
}
盡可能降低標(biāo)準(zhǔn)位置更新的準(zhǔn)確性
標(biāo)準(zhǔn)位置更新允許您通過設(shè)置location manager對象的desiredAccuracy屬性來指定從幾米到幾公里的精度,如清單14-3所示。請求比您需要的更高的精度會導(dǎo)致核心位置為額外的硬件供電,并浪費(fèi)不必要的精度。除非你的應(yīng)用程序確實(shí)需要知道用戶在幾米之內(nèi)的位置,否則不要將精度級別設(shè)置為“最佳”(kclocationaccuracybest)或最接近的10米(kclocationaccuracynearttenmeters)。另外,請注意,核心位置通常提供比您要求的更準(zhǔn)確的數(shù)據(jù)。例如,當(dāng)指定精度級別為3公里(kclocationAccuracythreekm)時,您可能會收到100米左右的精度。
默認(rèn)情況下,iOS設(shè)備上的標(biāo)準(zhǔn)位置更新以最佳的精度級別運(yùn)行。更改這些設(shè)置以符合應(yīng)用程序的要求。否則,你的應(yīng)用程序?qū)⒉槐匾乩速M(fèi)能源
清單14-3指定位置更新的準(zhǔn)確性
-(void)getLocationUpdate {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Set an accuracy level. The higher, the better for energy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
// Start location updates
[self.locationManager startUpdatingLocation];
}
如果精度與預(yù)期不符,則停止位置更新
如果你的應(yīng)用沒有收到預(yù)期準(zhǔn)確度的更新,你的應(yīng)用應(yīng)該檢查它正在收到的更新,并確定準(zhǔn)確度是在提高還是保持不變。如果精度沒有提高,很可能目前無法達(dá)到所需的精度水平。在這種情況下,請停止位置更新,稍后再試,這樣您的應(yīng)用程序就不會持續(xù)導(dǎo)致位置硬件斷電。
在后臺接收位置更新時自動暫停并指定活動類型
如果您的iOS應(yīng)用在后臺運(yùn)行時必須繼續(xù)監(jiān)視位置,請?jiān)凇?Xcode項(xiàng)目”>“功能”窗格中啟用后臺模式。選中“位置更新”復(fù)選框,如圖14-1所示。
圖14-1在應(yīng)用程序中啟用后臺位置更新

在iOS 9和更高版本中,無論部署目標(biāo)如何,還必須allowsBackgroundLocationUpdates將位置管理器對象的屬性設(shè)置為
YES,以接收后臺位置更新。默認(rèn)情況下,此屬性為NO,并且應(yīng)保持這種狀態(tài),直到您的應(yīng)用積極要求后臺位置更新為止。
確保將位置管理器對象的pausesLocationUpdatesAutomatically屬性設(shè)置YES為有助于節(jié)省電量。
設(shè)置activityType屬性以使“核心位置”知道您的應(yīng)用在給定時間執(zhí)行的位置活動類型,例如,如果您的應(yīng)用正在執(zhí)行健身跟蹤或汽車導(dǎo)航。請參閱CLActivityType以獲取活動類型列表。
指定這些設(shè)置有助于位置管理器確定最合適的時間來執(zhí)行位置更新。例如,如果系統(tǒng)確定用戶不在移動,則可以自動暫停后臺位置更新。
參見清單14-4。
重要stopUpdatingLocation當(dāng)不再需要位置更新時,即使已啟用自動暫停,也不要忘記調(diào)用位置管理器對象的方法。
-(void)startBackgroundLocationUpdates {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Set an accuracy level. The higher, the better for energy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
// Enable automatic pausing
self.locationManager.pausesLocationUpdatesAutomatically = YES;
// Specify the type of activity your app is currently performing
self.locationManager.activityType = CLActivityTypeFitness;
// Enable background location updates
self.locationManager.allowsBackgroundLocationUpdates = YES;
// Start location updates
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Perform location-based activity
...
// Stop location updates when they aren't needed anymore
[self.locationManager stopUpdatingLocation];
// Disable background location updates when they aren't needed anymore
self.locationManager.allowsBackgroundLocationUpdates = NO;
}
在后臺運(yùn)行時推遲位置更新
在具有GPS硬件的受支持設(shè)備上,您可以讓位置管理器在您的應(yīng)用程序在后臺運(yùn)行時推遲位置更新的交付。例如,跟蹤用戶在遠(yuǎn)足徑上位置的健身應(yīng)用可以將更新推遲到用戶移動一定距離或經(jīng)過一定時間后再進(jìn)行。然后,它可以一次處理所有更新。您可以deferredLocationUpdatesAvailable用來確定設(shè)備是否支持推遲的位置更新。
要推遲更新,請調(diào)用位置管理器對象的allowDeferredLocationUpdatesUntilTraveled:timeout:方法,并將其傳遞給距離和時間,該方法可能會在接收到下一個位置更新之前經(jīng)過。通常在locationManager:didUpdateLocations:委托方法中調(diào)用此方法,以便在收到延遲的位置更新時在適當(dāng)時再次延遲。
收到延遲的位置更新時,locationManager:didFinishDeferredUpdatesWithError:也會調(diào)用委托方法,您的應(yīng)用程序可以借此機(jī)會來調(diào)整行為以進(jìn)行下一次更新,例如增加或減少延遲距離和時間。參見清單14-5。
清單14-5根據(jù)距離和時間延遲后臺位置更新
-(void)startHikeLocationUpdates {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestWhenInUseAuthorization];
// Specify the type of activity your app is currently performing
self.locationManager.activityType = CLActivityTypeFitness;
// Start location updates
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// Add the new locations to the hike
[self.hike addLocations:locations];
// Defer updates until the user hikes a certain distance or a period of time has passed
if (!self.deferringUpdates) {
CLLocationDistance distance = self.hike.goal - self.hike.distance;
NSTimeInterval time = [self.nextUpdate timeIntervalSinceNow];
[self.locationManager allowDeferredLocationUpdatesUntilTraveled:distance timeout:time];
self.deferringUpdates = YES;
} }
-(void)locationManager:(CLLocationManager *)manager
didFinishDeferredUpdatesWithError:(NSError *)error {
// Stop deferring updates
self.deferringUpdates = NO;
// Adjust for the next goal
}
將位置更新限制為特定區(qū)域或位置
某些應(yīng)用不需要接收連續(xù)的位置更新,只需要知道用戶何時位于某個位置的特定距離內(nèi)即可。例如,雜貨應(yīng)用可以在用戶靠近商店時顯示新的優(yōu)惠券。有幾種核心位置API可以使您的應(yīng)用程序了解最新情況
注意
下述監(jiān)視技術(shù)僅提供進(jìn)入和退出通知。要確定收到通知時用戶的實(shí)際位置,必須調(diào)用位置管理器對象的requestLocation:或startUpdatingLocation:方法。這些監(jiān)視技術(shù)還要求授權(quán)狀態(tài)為kCLAuthorizationStatusAuthorizedAlways。
區(qū)域和信標(biāo)監(jiān)控
核心位置提供了兩種方法來檢測用戶進(jìn)入和離開特定區(qū)域。
- 地理區(qū)域監(jiān)視提供了地球上指定位置的出入通知。
- 當(dāng)用戶在發(fā)布iBeacon信息的低功耗藍(lán)牙設(shè)備范圍內(nèi)時,Beacon監(jiān)視會提供進(jìn)入和退出通知。
有關(guān)使用這些技術(shù)的詳細(xì)信息,請參閱地區(qū)監(jiān)測和iBeacon顯示在位置和地圖編程指南。
訪問監(jiān)控使應(yīng)用程序可以接收用戶頻繁或長時間訪問的特定位置(例如家庭,工作或喜歡的咖啡店)的出入通知。
要開始監(jiān)視訪問,請將代理分配給位置管理器對象并調(diào)用其startMonitoringVisits方法。請注意,調(diào)用此方法將啟用應(yīng)用程序中的所有訪問更新,而不僅僅是當(dāng)前委托的更新。啟用后,訪問事件將傳遞給locationManager:didVisit:委托的方法。如果在傳遞訪問事件時您的應(yīng)用未運(yùn)行,則會自動重新啟動您的應(yīng)用。當(dāng)不再需要訪問位置更新時,請致電stopMonitoringVisits,如清單14-6所示。
清單14-6使用訪問監(jiān)視來接收綁定到特定位置的更新
-(void)startVisitMonitoring {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestAlwaysAuthorization];
// Start monitoring for visits
[self.locationManager startMonitoringVisits];
}
-(void)stopVisitMonitoring {
[self.locationManager stopMonitoringVisits];
}
-(void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit {
// Perform location-based activity
...
}
僅在萬不得已時注冊重大更改位置更新
如果GPS級別的精度對您的應(yīng)用程序不是至關(guān)重要的,則您不需要連續(xù)跟蹤,并且區(qū)域或訪問監(jiān)控對于您的應(yīng)用程序來說就不太合適,則可以使用重大變化位置服務(wù)代替標(biāo)準(zhǔn)的位置服務(wù)。
重要
區(qū)域和訪問監(jiān)視對于大多數(shù)用例而言已足夠,并且在重大變化的位置更新之前應(yīng)始終予以考慮。重大變化的位置更新將全天候連續(xù)運(yùn)行,直到您將其停止為止,并且如果未有效利用,則實(shí)際上會導(dǎo)致更高的能耗。
要開始重大更改位置更新,請調(diào)用startMonitoringSignificantLocationChanges位置管理器對象的方法。完成后,調(diào)用stopMonitoringSignificantLocationChanges,如清單14-7所示。
注意
重大更改位置更新要求授權(quán)狀態(tài)為kCLAuthorizationStatusAuthorizedAlways。
清單14-7請求重大更改位置更新
-(void)startSignificantChangeLocationUpdates {
// Create a location manager object
self.locationManager = [[CLLocationManager alloc] init];
// Set the delegate
self.locationManager.delegate = self;
// Request location authorization
[self.locationManager requestAlwaysAuthorization];
// Start significant-change location updates
[self.locationManager startMonitoringSignificantLocationChanges];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
// Perform location-based activity
// Stop significant-change location updates when they aren't needed anymore
[self.locationManager stopMonitoringSignificantLocationChanges];
}