如何獲取電量消耗
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.h
和IOPSKeys.h
我們可以使用,同時需要將IOKit.framework
拖入工程。
//獲取電池能量
- (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
的計算,當無法減少時可以使用GCD
的dispatch_block_create_with_qos_class
指定Qos
爲QOS_CLASS_UTILITY
,在QOS_CLASS_UTILITY
模式下,系統對大量運算的電量消耗做了優化。
優化I/O操作
將碎片化的數據在內存
中存儲起來,進行聚合後,在進行存儲。減少 I/O
次數。
內存我們可以使用 NSCache
類,NSCache
是線程安全的,它會在達到預設緩存空間值時清理緩存,這時會觸發cache:willEvictObject:
方法,在這個方法裏進行I/O
操作。
對於數據讀取,應該首先檢測內存中的數據,先從內存中取,取不到再從磁盤中取。SDWebImage
就將獲取的圖片放到了NSCache
中,有效減少了I/O
操作
蘋果官方文檔 中,對減少耗電量進行了指導說明