消耗取決於不一樣的因素:html
最佳實踐:git
智能的網絡訪問管理可讓應用響應的更快,並有助於延長電池的壽命。應避免在沒有鏈接WiFi的狀況下進行高帶寬消耗的操做,好比視頻流。蜂窩無線系統(LTE,4G,3G等)對電量的消耗都遠大於WiFi信號。根源在於LTE設備基於多輸入,多輸出技術,使用多個併發信號以維護兩端的LTE連接。相似的,全部的蜂窩數據連接都會按期掃描以尋找更強的信號。github
官方Reachability示例代碼:https://developer.apple.com/library/content/samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2 Reachabilitypod:https://github.com/tonymillion/Reachability算法
檢查網絡狀態:api
-(BOOL)isAPIServerReachable{ Reachability *r = [Reachability reachabilityWithHostName:@"api.yourdomain.com"];//1.檢查服務器域名是否可達 return r.isReachable;//2.對網絡狀態NetworkStatus進行優化 } -(void)performNetWorkOperation:(NSDictionary *) params completion:(void(^)(NSError *,id)) completion{//3.提供id類型的結果或NSError類型錯誤 if (![self isAPIServerReachable]){ // [self enqueueRequest:params completion:completion];4.對操做進行排隊 NSError *err = [[NSError alloc]initWithDomain:@"network" code:1 userInfo:nil];//5.code需自定義常量 }else{ // [self doNetworkOperation:params completion:completion];//6.網絡可用觸發請求 } }
監控網絡並執行隊列:服務器
[@interface](https://my.oschina.net/u/996807) HPNewworkOps () [@property](https://my.oschina.net/property) (nonatomic , readonly) BOOL isAPISeverReachable;//檢測網絡是否可用標識 [@property](https://my.oschina.net/property) (nonatomic , strong) Reachability *reachability;//監聽狀態 本例暫監視WiFi網絡的變化 @property (nonatomic , strong) NSOperationQueue *networkOperationQueue;//保留隊列的操做,該隊列一次只容許執行一個操做 @property (nonatomic , strong) NSBlockOperation *operation; @end @implementation HPNewworkOps -(id)init{ if (self == [super init]){ self.reachability = [Reachability reachabilityWithHostName:@"www.baidu.com"]; self.reachability.reachableOnWWAN = NO; self.networkOperationQueue = [[NSOperationQueue alloc]init]; self.networkOperationQueue.maxConcurrentOperationCount = 1; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkStatusChanged:) name:kReachabilityChangedNotification object:nil]; } return self; } -(void)networkStatusChanged:(Reachability *)reachability{//根據網絡的可用狀況,通知的接受者掛起或恢復隊列 if (reachability.isReachable != ReachableViaWiFi){ self.networkOperationQueue.suspended = YES; }else{ self.networkOperationQueue.suspended = NO; } } -(BOOL)isAPISeverReachable{ return self.reachability.isReachable; } -(void)performNetWorkOperation:(NSDictionary *)param completion:(void(^)(NSError *,id)) completion{//老是將網絡操做送入隊列中 self.operation = [NSBlockOperation blockOperationWithBlock:^{ [self enqueueRequest:param completion:completion];//對網絡操做進行排隊 }]; [self.networkOperationQueue addOperation:self.operation]; } -(void)enqueueRequest:(NSDictionary *)params completion:(void(^)(NSError *,id)) completion{ AFHTTPSessionManager *op = [AFHTTPSessionManager manager]; op.requestSerializer.timeoutInterval = 10; [op POST:@"www.baidu.com" parameters:params progress:^(NSProgress * _Nonnull uploadProgress) { } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { completion(nil,responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { completion(error,nil); }]; } @end
一個掛起的隊列僅僅意味着後續操做在其恢復以前不會被執行,操做只有完成後纔會從隊列中移除。然而,爲了完成執行,必須先啓動操做。由於掛起的隊列不會啓動任何新的操做,因此它也不會移除任何正在排隊且未被執行的操做網絡
使用GPS計算座標須要肯定兩點信息:數據結構
- (void)viewDidLoad { [super viewDidLoad]; self.manager = [[CLLocationManager alloc]init]; self.manager.delegate = self; self.manager.distanceFilter = kCLDistanceFilterNone;//觀察全部距離的變化 self.manager.desiredAccuracy = kCLLocationAccuracyBest;//按照最大精度初始化管理器 if (IOS8_OR_LATER_NEW){ [self.manager requestAlwaysAuthorization]; //iOS8 特定API用於應用活動時申請使用定位服務 } [self.manager stopUpdatingLocation]; } -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{ CLLocation *loc = [locations lastObject]; //使用定位信息 }
無需跟蹤位置變化時調用stopUpdatingLocation,向終端用戶提供關閉非必要功能的選項是個不錯的設計。併發
按期集中短暫的使用網絡,而不是持續的保持活動的數據流,才能更好的節省消耗。app
應用進入後臺調用監聽(startUpdatingLocation也會喚起回調,startMonitoringSignificantLocationChanges在程序被殺掉時調用更好)
- (void)applicationDidEnterBackground:(UIApplication *)application { [self.manager startMonitoringSignificantLocationChanges]; // [self.manager startUpdatingLocation]; } - (void)applicationWillEnterForeground:(UIApplication *)application { [self.manager stopMonitoringSignificantLocationChanges]; }
後臺定位:http://adad184.com/2015/07/22/how-to-deal-with-background-location-update/
當應用位於後臺時,任何定時器或線程都會掛起。但若是你在應用位於後臺狀態時申請了定位,那麼應用會在每次收到更新後被短暫喚醒。在此期間,線程和定時器都會被喚醒。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if(launchOptions[UIApplicationLaunchOptionsLocationKey]){//被殺掉的APP 在後臺被系統喚醒時 launchOptions會包含UIApplicationLaunchOptionsLocationKey字段來進行標識 [self.manager startMonitoringSignificantLocationChanges];//從新監聽 } }
經過監聽UIApplicationWillResignActiveNotification或UIApplicationDidEnterBackgroundNotification的通知事件來暫停或中止動畫,也能夠經過監聽UIApplicationDidBecomeActiveNotification的通知事件來恢復動畫。
[[UIApplication sharedApplication]setIdleTimerDisabled:YES];//保持屏幕常量
官方使用外部屏幕demo:https://apple.co/1jauUnu
@interface HPMultiScreenViewController () @property (nonatomic , strong) UIWindow *secondWindow; @end @implementation HPMultiScreenViewController - (void)viewDidLoad { [super viewDidLoad]; [self registerNotifications]; } -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; [self updateScreens]; } -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [self disconnectFromScreen]; } -(void)disconnectFromScreen{ if (self.secondWindow != nil){ //斷開連接並準備釋放內存 self.secondWindow.rootViewController = nil; self.secondWindow.hidden = YES; self.secondWindow = nil; } } -(void)updateScreens{ NSArray *screens = [UIScreen screens]; if (screens.count > 1){ UIScreen *secondScreen = (UIScreen *)[screens objectAtIndex:1]; CGRect rect = secondScreen.bounds; if (self.secondWindow == nil){ self.secondWindow = [[UIWindow alloc]initWithFrame:rect]; self.secondWindow.screen = secondScreen; HPScreen2ViewController *svc = [[HPScreen2ViewController alloc]init]; //設置svc的其餘屬性以完整的對它初始化 // svc.parent = self; self.secondWindow.rootViewController = svc; } self.secondWindow.hidden = NO; }else{ [self disconnectFromScreen]; } } -(void)dealloc{ [self unregisterNotifications]; } -(void)registerNotifications{ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(screenChanged:) name:UIScreenDidConnectNotification object:nil]; [nc addObserver:self selector:@selector(screenChanged:) name:UIScreenDidDisconnectNotification object:nil]; } -(void)screenChanged:(NSNotification *) notification{ [self updateScreens]; } -(void)unregisterNotifications{ [[NSNotificationCenter defaultCenter] removeObserver:self]; } @end
在屏幕之間交換UI
-(void)swapScreens:(UIWindow *)currentWindow newWindow:(UIWindow *)newWindow{ NSArray *screens = [UIScreen screens]; UIScreen *deviceScreen = [screens objectAtIndex:0]; UIScreen *extScreen = [screens objectAtIndex:1]; currentWindow.screen = extScreen; newWindow.screen = deviceScreen; }
一個智能的應用會考慮電池的電量和自身的狀態,從而決定是否要真正的執行資源密集消耗性操做。
//使用電量級別和充電狀態進行條件處理 -(BOOL)shouldProceedWithMinLevel:(NSInteger)minLevel{ UIDevice *device = [UIDevice currentDevice]; device.batteryMonitoringEnabled = YES; UIDeviceBatteryState state = device.batteryState; if (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull){//在充電或電池已經充滿的狀態能夠進行操做 return YES; } NSUInteger batteryLevel = (NSUInteger) (device.batteryLevel * 100);//按本身設定的電池範圍操做 if (batteryLevel >= minLevel){ return YES; } return NO; }
對CPU的利用率:
-(float)appCPUUsage{ kern_return_t kr; task_info_data_t info; mach_msg_type_number_t infoCount = TASK_INFO_MAX; kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)info, &infoCount); if (kr != KERN_SUCCESS){ return -1; } thread_array_t thread_list; mach_msg_type_number_t thread_count; thread_info_data_t thinfo; mach_msg_type_number_t thread_info_count; thread_basic_info_t basic_info_th; kr = task_threads(mach_task_self(), &thread_list, &thread_count); if (kr != KERN_SUCCESS){ return -1; } float tot_cpu = 0; int j; for (j = 0 ;j< thread_count ; j++){ thread_info_count = THREAD_INFO_MAX; kr = thread_info(thread_list[j], THREAD_BASIC_INFO, (thread_info_t)thinfo,&thread_info_count); if (kr != KERN_SUCCESS){ return -1; } basic_info_th =(thread_basic_info_t)thinfo; if (!(basic_info_th->flags & TH_FLAGS_IDLE)) { tot_cpu += basic_info_th -> cpu_usage / (float)TH_USAGE_SCALE * 100.0; } } vm_deallocate(mach_thread_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t)); return tot_cpu; }
確保對電量的謹慎使用:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; BOOL prompt = [defaults boolForKey:@"promptForBattery"]; NSInteger minLevel = [defaults integerForKey:@"minBatterKevel"]; BOOL canAutoProceed = [self shouldProceedWithMinLevel:minLevel]; if (canAutoProceed){ //執行密集操做 }else{ if (prompt){//低電量進行提示 }else{ } }