消耗取决于不一样的因素: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{ } }