iOS開發-App電量消耗以及CPU佔用

如何獲取電量消耗

UIDevice 獲取

- (float)batteryValue {
    [UIDevice currentDevice].batteryMonitoringEnabled = YES;
    return [UIDevice currentDevice].batteryLevel;
}

這個值以0.05遞變的,所以並不精準。

IOKit

IOKit Framework 是專門用於硬件和內核通信的,我們可以通過IOKit Framework 來獲取設備電量信息。

IOKit Framework 在iOS庫中頭沒有,我們可以找到Mac端的庫,裏面有相關的頭文件。

例如/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework

或者你可以從我的 百度網盤下載
鏈接:https://pan.baidu.com/s/1vh6SyCSVz_kz4j-eazNJIA
密碼:3gdv

IOPowerSources.hIOPSKeys.h我們可以使用,同時需要將IOKit.framework拖入工程。

IOPowerSources.h的官方文檔說明

//獲取電池能量
- (double)getCurrentBatteryLevel {
    [UIDevice currentDevice].batteryMonitoringEnabled = YES;
    CFTypeRef blob = IOPSCopyPowerSourcesInfo();
    CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
    CFDictionaryRef pSource = NULL;
    const void *psValue;
    long numOfSources = CFArrayGetCount(sources);
    if (numOfSources == 0) {
        NSLog(@"Error in CFArrayGetCount");
        return -1.0f;
    }
    
    for (int i = 0 ; i < numOfSources ; i++) {
        pSource = IOPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i));
        if (!pSource) {
            NSLog(@"Error in IOPSGetPowerSourceDescription");
            return -1.0f;
        }
        psValue = (CFStringRef)CFDictionaryGetValue(pSource, CFSTR(kIOPSNameKey));
        int curCapacity = 0;
        int maxCapacity = 0;
        double percent;
        psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSCurrentCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
        psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSMaxCapacityKey));
        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
        //如果顯示百分比
        percent = ((double)curCapacity/(double)maxCapacity) * 100.0f;
        return percent;
    }
    
    return -1.0f;
}

電量分析

獲取了電量值之後,如何分析呢?

電量消耗大,另一方面可能意味着CPU使用率高,我們可以通過獲取各個線程的CPU使用率來判斷是哪個線程,然後通過線程堆棧來判斷方法函數。

通過 task_threads 接口獲取到線程情況,通過thread_basic_info 字段的cpu_usage來判斷使用率,再進行獲取堆棧。

struct thread_basic_info {
	time_value_t    user_time;      /* user run time */
	time_value_t    system_time;    /* system run time */
	integer_t       cpu_usage;      /* scaled cpu usage percentage */
	policy_t        policy;         /* scheduling policy in effect */
	integer_t       run_state;      /* run state (see below) */
	integer_t       flags;          /* various flags (see below) */
	integer_t       suspend_count;  /* suspend count for thread */
	integer_t       sleep_time;     /* number of seconds that thread
	                                 *  has been sleeping */
};

代碼如下

//輪詢檢查多個線程 cpu 情況
+ (void)updateCPU {
    thread_act_array_t threads;
    mach_msg_type_number_t threadCount = 0;
    const task_t thisTask = mach_task_self();
    kern_return_t kr = task_threads(thisTask, &threads, &threadCount);
    if (kr != KERN_SUCCESS) {
        return;
    }
    for (int i = 0; i < threadCount; i++) {
        thread_info_data_t threadInfo;
        thread_basic_info_t threadBaseInfo;
        mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX;
        if (thread_info((thread_act_t)threads[i], THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount) == KERN_SUCCESS) {
            threadBaseInfo = (thread_basic_info_t)threadInfo;
            if (!(threadBaseInfo->flags & TH_FLAGS_IDLE)) {
                integer_t cpuUsage = threadBaseInfo->cpu_usage / 10;
                if (cpuUsage > CPUMONITORRATE) {
                    //cup 消耗大於設置值時打印和記錄堆棧
                    
                }
            }
        }
    }
}

關於堆棧信息如何獲取,在下一篇文章進行說明。

電量優化

優化CPU

減少CPU的計算,當無法減少時可以使用GCDdispatch_block_create_with_qos_class指定QosQOS_CLASS_UTILITY,在QOS_CLASS_UTILITY模式下,系統對大量運算的電量消耗做了優化。

優化I/O操作

將碎片化的數據在內存中存儲起來,進行聚合後,在進行存儲。減少 I/O 次數。

內存我們可以使用 NSCache 類,NSCache是線程安全的,它會在達到預設緩存空間值時清理緩存,這時會觸發cache:willEvictObject:方法,在這個方法裏進行I/O操作。

對於數據讀取,應該首先檢測內存中的數據,先從內存中取,取不到再從磁盤中取。SDWebImage就將獲取的圖片放到了NSCache中,有效減少了I/O操作

蘋果官方文檔 中,對減少耗電量進行了指導說明

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章