获取电量
通过IOKit就能获取。
需要导入IOPSKeys.h、IOPowerSources.h 、IOKit
-(double) getBatteryLevel{
// 返回电量信息
CFTypeRef blob = IOPSCopyPowerSourcesInfo();
// 返回电量句柄列表数据
CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
CFDictionaryRef pSource = NULL;
const void *psValue;
// 返回数组大小
int 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 percentage;
psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSCurrentCapacityKey));
CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSMaxCapacityKey));
CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
percentage = ((double) curCapacity / (double) maxCapacity * 100.0f);
NSLog(@"curCapacity : %d / maxCapacity: %d , percentage: %.1f ", curCapacity, maxCapacity, percentage);
return percentage;
}
return -1.
诊断电量问题
关于电量的使用,主要是CPU消耗与IO数据。而目前能诊断的只有CPU使用大头这块。
CPU消耗这一方面,通过之前iOS崩溃笔记里的 thread_basic_info 可以获取到所有线程的cpu_usage,也就是CPU使用率。
大于90%时,就可以记录此时的方法堆栈,也就是消耗大头所在。
// 轮询检查多个线程 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 > 90) {
//cup 消耗大于 90 时打印和记录堆栈
NSString *reStr = smStackOfThread(threads[i]);
// 记录数据库中
[[[SMLagDB shareInstance] increaseWithStackString:reStr] subscribeNext:^(id x) {}];
NSLog(@"CPU useage overload thread stack:\n%@",reStr);
}
}
}
}
}
优化电量
之前说过,消耗大头是CPU计算与I/O操作。
CPU的消耗节省,就是将负责的计算尽可能交给后台。也为我们省了很多事。。
如果必须处理复杂的计算,可以将方法队列的QOS设置为QOS_CLASS_UTILITY,系统对这种QOS的队列有计算方面的优化。
设置方式为,可通过GCD的dispatch_block_create_with_qos_class方法指定队列的QOS为QOS_CLASS_UTILITY。
I/O操作优化,将碎片化的数据磁盘存储操作延后,先在内存中聚合,在进行磁盘存储。碎片化的数据聚合,在内存中进行存储的机制可通过NSCache来完成。
NSCache是线程安全的。NSCache可在达到预设缓存空间值时进行清理缓存,这时会触发cache:willEvictObject:方法的回调,在回调里可以对数据进行I/O操作,达到将聚合的数据I/O延后的目的。
(简单说,用NSCache操作数据。先用NSCache将数据存储在内存,当预设的内存缓存使用要爆满时会调用cache:willEvictObject:方法的回调,然后在回调里将数据存储到磁盘。)
I/O操作的次数少了,对电量的消耗也就少了。
SDWebImage中相关的:
- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key {
return [self.memCache objectForKey:key];
}
- (UIImage *)imageFromDiskCacheForKey:(NSString *)key {
// 检查 NSCache 里是否有
UIImage *image = [self imageFromMemoryCacheForKey:key];
if (image) {
return image;
}
// 从磁盘里读
UIImage *diskImage = [self diskImageForKey:key];
if (diskImage && self.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost];
}
return diskImage;
}
苹果提供的优化指南:Energy Efficiency Guide for iOS Apps
WWDC的主题:Writing Energy Efficient Apps
网友评论