Power consumption is an important factor to address when writing high-performance code, and in terms of execution time and CPU utilization, we need to implement not only efficient data structures and algorithms, There are other factors to consider. If an application is a battery black hole, no one will like it. In addition to the CPU, there are hardware modules: network hardware, Bluetooth,GPS, microphone, accelerometer, camera, speaker, and screen. We can look at the article with the following questions:

  • What are the key areas of power consumption
  • How to reduce electricity consumption
  • How to analyze power, CPU, and resource usage in IOS apps

A CPU

The CPU is the main hardware used by the application, whether the user is directly using it or not, and the application still consumes CPU resources during background operations and processing of push notifications

The more you compute, the more power you consume. Older devices consume more power to perform the same basic operation (changing the battery), and the amount of computation consumed depends on different factors

  • The processing of data
  • Data size to process – A larger display allows software to display more information in a single view, but it also means processing more data
  • Algorithms and data structures for processing data
  • The number of times an update has been performed, especially after a data update, triggering an update to the app’s state or UI. (Push notifications received by the app can also cause data updates, and you need to update the UI if the user is using the app.)

There is no single rule that can reduce the number of executions on a device, and many rules depend on the nature of the operation. Here are some best practices that can be applied in an application

  • For example, when you’re sorting, if the list has less than 43 instances, insert sort is better than merge sort, but for 286 instances, you should use quicksort, and use double-pivot quicksort in preference to traditional single-pivot quicksort
  • If the application from the server to accept data, to minimize the need of processing on the client For example, if a text needs to render the client, as far as possible clean up the data to the server I used to do a project, because of the realization of the server service is mainly used for desktop users, so the returned text contains HTML tags, Cleaning up HTML tags is not done on the client side, but on the server side, which reduces computation and processing time on the device
  • The disadvantage of aHEAD-time (AOT) dynamic compilation is that it forces the user to wait for the operation to complete. However, radical AOT processing will lead to the waste of computing resources, requiring precise and quantitative AOT processing according to the application and device. For example, when rendering a set of records in a UITableView, it is not wise to process the entire record in the load list. Depending on the height of the cell, if the device can render N records, then 3N or 4N is an ideal data load size. Similarly, if the user slides quickly, the record should not be loaded immediately, but should be delayed from dropping to a certain threshold with scroll speed. The exact threshold should be determined by the processing time of each cell and the complexity of the cell’s UI

Two network

Smart network access management makes applications more responsive and helps prolong battery life. When the network is inaccessible, subsequent network requests should be deferred until the network connection is restored. In addition, high broadband consumption operations without WiFi connection should be avoided. For example, video streaming, as we all know, cellular wireless systems (LTE,4G,3G, etc.) consume far more power than WiFi signals, The root cause is that LTE devices are based on multi-input, multi-output technology, using multiple concurrent signals to maintain LTE links at both ends. Similarly, all cellular data links are scanned periodically for stronger signals. Therefore: we need

  • Before performing any network operations, check that the appropriate network connection is available
  • Continuously monitor network availability and give appropriate feedback when link status changes

Location manager and GPS

This knowledge point in my project did not use positioning related functions, but also summarized the knowledge point in the book useful positioning function friends can refer to this knowledge point to optimize their app

We all know that location services are power-hungry, and using GPS to calculate coordinates requires two things:

  • Time lock Each GPS satellite broadcasts a unique 1023 bit random number every millisecsec, so the data propagation rate is 1.024Mbit/s. The GPS receiver chip must be correctly aligned with the satellite’s time lock slot
  • A frequency-locked GPS receiver must calculate the signal error caused by doppler offset caused by the receiver’s relative motion with the satellite

Computing coordinates constantly uses CPU and GPS hardware resources, so they can quickly drain battery power. Let’s take a look at the typical code that initializes CLLocationManager and receives geolocation updates efficiently


#import "LLLocationViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface LLLocationViewController ()<CLLocationManagerDelegate>
@property (nonatomic, strong)CLLocationManager *manager;
@end

@implementation LLLocationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.manager = [[CLLocationManager alloc]init];
    self.manager.delegate = self;    
}

- (void)enableLocationButtonClick:(UIButton *)sender{ self.manager.distanceFilter = kCLDistanceFilterNone; / / in accordance with the self. The maximum precision initialization manager manager. DesiredAccuracy = kCLLocationAccuracyBest;if(IS_IOS8) { [self.manager requestWhenInUseAuthorization]; } [self.manager startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{ CLLocation  *loc = [locations lastObject]; // Use location information}Copy the code
3.1 Optimal initialization
  • distanceFilterAs soon as the device moves beyond the minimum distance, the distance filter causes the manager to change the value of the delegate objectLocationManager:didUpdateLocations:Event notification changes at a distance of M
  • DesiredAccuracy directly affects the number of antennas used, and then affects the battery consumption. The selection of precision level depends on the specific purpose of the application. Precision is an enumeration. We should choose the precision level appropriately according to different requirements

Distance filters are only software level filters, and accuracy levels affect the use of physical antennas. When the delegate LocationManager: didUpdateLocations: is called, using distance range wider transition device affects only the interval. On the other hand, higher accuracy levels mean more moving antennas, which consume more power

3.2 Turn off irrelevant features

Determine when you need to track location changes and call the startUpdatingLocation method when tracing is required and the stopUpdatingLocation method when tracing is not required.

Location tracking should also be turned off when the app is running in the background or when the user is not chatting with someone else. In other words, it should be turned off when browsing your media library, checking your friends list, or adjusting your app Settings

3.3 Use the network only when necessary

To maximize battery efficiency, IOS keeps wireless networks off as much as possible. When an application needs to establish a network connection, IOS takes the opportunity to share the network session with the background application so that some low-priority tasks, such as push notifications and receiving emails, can be handled. The key is that each time the user establishes a network connection, the network hardware stays active for a few more seconds after the connection is completed. Each centralized network communication consumes a lot of power. To mitigate this, your software needs to use the network with reservation. Instead of a continuous stream of active data, the network should be used periodically and intensively for short periods. Only then will the network hardware have a chance to shut down

3.4 Background Location Service

CLLocationManager provides an alternative method to monitor position updates. [the self. The manager startMonitoringSignificantLocationChanges] can help you in further distance tracking movement. The exact value is determined internally and is independent of the distanceFilter Using this model can continue to track movement after application into the background, typically perform startMonitoringSignificantLocationChanges method when applied into the background, and execute when the application back to the front desk, startUpdatingLocation code as follows

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [self.manager stopUpdatingLocation];
    [self.manager startMonitoringSignificantLocationChanges];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {    
    [self.manager stopMonitoringSignificantLocationChanges];
    [self.manager startUpdatingLocation];    
}
Copy the code
3.5 Restart the Application after it is shut down

Applications in the background may be shut down when other applications need more resources. In this case, Application :(UIApplication *)application :(UIApplication *)application DidFinishLaunchingWithOptions launchOptions method: (NSDictionary *) will be key for code UIApplicationLaunchOptionsLocationKey entry is as follows: Reinitialize the listener after the application is closed

- (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // After an application is shut down due to lack of resources, monitor whether the application is restarted due to location changesif(launchOptions [UIApplicationLaunchOptionsLocationKey]) {/ / open position monitoring [self. Manager startMonitoringSignificantLocationChanges]; }}Copy the code

### Four screens are very power-hungry, and the bigger the screen, the more power-hungry it is. Of course, if your application is running in the foreground and interacting with the user, you’re going to use the screen and consume power. There are still some ways to optimize screen usage

4.1 the animation

Animation is used when the application is in the foreground, and suspended as soon as the application is in the background. Usually, you can do this by listening in UIApplicationWillResignActiveNotification UIApplicationDIdEnterBackgroundNotification notification events to pause or stop the animation, but can be by listening UIApplicationD IdBecomeActiveNotification notification events to restore animation

4.2 Video Playback

In my last company, I made a video App, and I used this technology to keep the screen steady

It is best to keep the screen constant for the duration of the video. You can do this using the idleTimerDisabled property of the UIApplication object. Once set to YES, it prevents the screen from sleeping so that it is always on. Similar to animation, you can release and acquire locks via notifications from the corresponding app

More than 4.3 screen

Using the screen is much more complicated than sleeping locks or pausing/resuming animations

If you’re playing movies or running animations, you can move them from the device’s screen to the external screen, leaving only the most basic Settings on the device’s screen, which can reduce screen updates on the device and thus extend battery life

Typical code for handling this scenario involves the following steps

  • 1 Monitors the number of screens during startup. If the number of screens is greater than 1, switch
  • 2 Listen for notifications of links and disconnections on the screen. If a new screen is added, switch. If all external screens are removed, the default display is restored

@interface LLMultiScreenViewController ()
@property (nonatomic, strong)UIWindow  *secondWindow;
@end

@implementation LLMultiScreenViewController

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    [self updateScreens];
}

- (void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];
    [self disconnectFromScreen];
    
}

- (void)viewDidLoad {
    [super viewDidLoad];    
    [self registerNotifications];    
}

- (void)registerNotifications{
    
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(scrensChanged:) name:UIScreenDidConnectNotification object:nil];
}

- (void)scrensChanged:(NSNotification *)nofi{
    [self updateScreens];
}

- (void)updateScreens{
    
    NSArray *screens = [UIScreen screens];
    if (screens.count > 1) {
        UIScreen *secondScreen = [screens objectAtIndex:1];
        CGRect rect =secondScreen.bounds;
        if (self.secondWindow == nil) {
            self.secondWindow = [[UIWindow alloc]initWithFrame:rect];
            self.secondWindow.screen = secondScreen;
            
            LLScreen2ViewController *svc = [[LLScreen2ViewController alloc]init];
            svc.parent = self;
            self.secondWindow.rootViewController = svc;
        }
        self.secondWindow.hidden = NO;
    }else{
        [self disconnectFromScreen];
    }
}

- (void)disconnectFromScreen{
    
    if(self.secondWindow ! = nil) {/ / disconnected and release the memory self. SecondWindow. The rootViewController = nil; self.secondWindow.hidden = YES; self.secondWindow = nil; } } - (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self]; }Copy the code

5 Other Hardware

When your application goes into the background, you should release locks on these hardware:

  • bluetooth
  • The camera
  • Speakers, unless the application is music
  • The microphone

Basic rule: Only interact with these hardware when the application is in the foreground, and stop interacting when the application is in the background

Speakers and wireless Bluetooth are exceptions. If you are developing music, radio, or other audio applications, you will need to continue using the speakers after the application has gone into the background. Don’t let the screen remain constant just for audio playback purposes. Similarly, if your application has unfinished data transfers, you need to continue using Wireless Bluetooth while your application is in the background, for example, transferring files to other devices

Battery power and code perception

I found that mobike’s mini program works well. If you scan the QR code by riding at night, you need to turn on the flash to illuminate the QR code. However, if your phone is in a low battery, your flash cannot be turned on. This one detail shows that user experience is important, and it will make sure that your phone doesn’t shut down because of the flash in the first place

An intelligent application takes into account the battery level and its own state to decide whether to perform a resource-intensive operation. Another valuable point is the judgment of charging, determining whether the device is in a charging state

Take a look at the code implementation here

- (BOOL)shouldProceedWithMinLevel:(NSUInteger)minLevel{ UIDevice *device = [UIDevice currentDevice]; / / open the battery monitoring device. BatteryMonitoringEnabled = YES; UIDeviceBatteryState state = device.batteryState; // Any operation can be performed when charging or the battery is fully chargedif (state == UIDeviceBatteryStateCharging ||
        state == UIDeviceBatteryStateFull) {
        returnYES; } // The batteryLevel returned by UIdevice ranges from 0.00 to 1.00 NSUInteger batteryLevel = (NSUInteger)(device.batteryLevel * 100);if (batteryLevel >= minLevel) {
        return YES;
    }
    return NO;
}
Copy the code

We can also get the CPU utilization of the application

// Import these two header files#import <mach/mach.h>
#import <assert.h>

- (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, 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, 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/TH_USAGE_SCALE * 100.0; } } vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));return tot_cpu;
    
}

Copy the code

Alert the user when the remaining battery is low, and request permission to perform power-intensive operations — of course, only with the user’s consent — always with an indicator (the percentage of the progress bar) showing the progress of a long task, including an upcoming calculation on the device or just downloading something. Provide users with estimates of progress to help them decide if they need to charge their devices

Vii Best Practices

The following best practices ensure that power usage is prudent, and applications can use power efficiently by following these guidelines.

  • Minimize hardware usage. In other words, work with the hardware as late as possible and end it as soon as you finish the task
  • Before undertaking intensive tasks, check the battery level and charging status
  • When the battery is low, the system prompts the user whether to perform the task, and performs the task after the user agrees
  • Or provide Settings that allow the user to define a threshold of power to prompt the user before performing a stealth operation

The following code shows setting the power threshold to prompt the user.


- (IBAction)onIntensiveOperationButtonClick:(id)sender {
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    BOOL prompt = [defaults boolForKey:@"promptForBattery"];
    int minLevel = [defaults integerForKey:@"minBatteryLevel"];
    
    BOOL canAutoProceed = [self shouldProceeWithMinLevel:minLevel];
    
    if (canAutoProceed) {
        [self executeIntensiveOperation];
    }else{
        
        if (prompt) {
            UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"Tip" message:@"The electric quantity is below the minimum value, do you want to continue?" delegate: self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Sure"];
            [view show];
        }else{
            
            [self queueIntensiveOperation];
        }
    }
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    
    if (buttonIndex == 0) {
        [self queueIntensiveOperation];
    }else{ [self executeIntensiveOperation]; }}Copy the code

The code is illustrated below

  • The Settings consist of two entries:promptForBattery(Apply the toggle switch in the Settings to indicate whether to give a hint when the battery is low) andminiBatteryLevel(A slider in the range 0 to 100, indicating the minimum charge —— in this case, the user can adjust), developers applying in real projects typically preset thresholds based on the complexity and intensity of the operation. Different intensive operations may have different minimum power requirements
  • Before actually performing intensive operations, check whether the current battery is sufficient or whether the phone is charging. This is the logic we use to determine whether we can proceed with the following process. You can have your own customization in the picture – minimum charge and charging status

Users always with mobile phones, so power-saving code is particularly important, after all, mobile phones mobile power supply is not everywhere, but now the street of Beijing electric charge sharing seems very good I go shopping street, often can use electric charge, but as far as possible for the user to save electricity in failing to reduce the complexity of tasks, Providing a battery-sensitive solution that alerts users when appropriate will make them feel good and therefore become a permanent user of your APP