iOS 获取内存信息与NSCache用法说明

释放双眼,带上耳机,听听看~!

一.获取内存使用情况

获取iOS App运行时内存,可以通过如下模块

#import<sys/sysctl.h> 
#import<mach/mach.h>

获取cpu核心数

unsigned int countOfCores()  
{  
    unsigned int ncpu;  
    size_t len = sizeof(ncpu);  
    sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0);  
      
    return ncpu;  
}  

获取方式如下,获取内存可以用空间

//获取当前设备可用内存,单位MB
 + (double)availableMemory{
      vm_statistics_data_t vmStats;
      mach_msg_type_number_t infoCount = HOST_VM_INFO_COUNT;
      kern_return_t kernReturn = host_statistics(mach_host_self(),
                                           HOST_VM_INFO,
                                           (host_info_t)&vmStats,
                                           &infoCount);

    if (kernReturn != KERN_SUCCESS) {
    return NSNotFound;
    }
    return ((vm_page_size * vmStats.free_count)/1024.0)/1024.0;
}



获取当前内存占用情况

//获取当前任务所占用内存,单位MB
+ (double)usedMemory{
    task_basic_info_data_t taskInfo;
    mach_msg_type_number_t infoCount = TASK_BASIC_INFO_COUNT;
    kern_return_t kernReturn = task_info(mach_task_self(),
                                     TASK_BASIC_INFO,
                                     (task_info_t)&taskInfo,
                                     &infoCount);

      if (kernReturn != KERN_SUCCESS) {
      return NSNotFound;
      }
      return taskInfo.resident_size/1024.0/1024.0;
}

获取app运行总内存

double memoryTotalSize = [SystemCpu availableMemory] + [SystemCpu usedMemory]

 

二、NSCache使用

1.NSCache的用法和NSMutableDictionary的区别

  • NSCache 是可以自动释放内存一部分的(当内存吃紧时,自动删除一些项目,并不是释放NSCache实例)。
  • NSCache 是线程安全的,我们可以在不同的线程中添加,删除和查询缓存中的对象。NSMutable默认都是不安全的。注意,多线程情况下,NSCache仍然可能不够安全,需要加锁。
  • NSCache  一个缓存对象不会拷贝key对象,而是直接引用key。

2.NSCache缓存图片

NSCache具备线程安全、自动释放Cache Item对象的特性,可以用来实现二级缓存。

#import "ViewController.h"
#import "WJCellItem.h"
@interface ViewController ()
//定义数组来存储从plist中加载的数据
@property (strong,nonatomic)NSArray *dataArr;
//在内存中存储图片的容器
@property (strong,nonatomic)NSCache *images;
//存储操作的字典
@property (strong,nonatomic)NSMutableDictionary *operations;
//队列
@property (strong,nonatomic)NSOperationQueue *queue;
@end

@implementation ViewController
//懒加载创建存储数据的数组
-(NSArray *)dataArr{
    if (_dataArr==nil) {
        NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
        NSArray *array=[NSArray arrayWithContentsOfFile:path];
        NSMutableArray *arrM=[NSMutableArray array];
        for (NSDictionary *dict in array) {
            //把从数组中取出来的字典包装成模型
            WJCellItem *item=[WJCellItem cellItemWithDict:dict];
            [arrM addObject:item];
        }
        _dataArr=arrM;
    }
    return _dataArr;
}
//懒加载创建字典
-(NSMutableDictionary *)operations{
    if (_operations==nil) {
        _operations=[NSMutableDictionary dictionary];
    }
    return _operations;
}
//懒加载创建队列
-(NSOperationQueue *)queue{
    if (_queue==nil) {
        _queue=[[NSOperationQueue alloc]init];
    }
    return _queue;
}
//懒加载创建NSCache
-(NSCache *)images{
    if (_images==nil) {
        _images=[[NSCache alloc]init];
        //最多缓存100张图片
        _images.countLimit=100;
    }
    return _images;
}

//整个tableView只有一组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}
//每一组有多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.dataArr.count;
}
//每一行cell的内容
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    //设置cell的标示
    static NSString *ID=@"cell";
    //tableViwe的重用机制,先从缓冲池里找有没有对应标示的cell
    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
    //如果在缓存池里找不到再来创建
    if (cell==nil) {
        cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];

    }
    //取出模型,给cell设置数据
    WJCellItem *item=self.dataArr[indexPath.row];
    cell.textLabel.text=item.name;
    cell.detailTextLabel.text=item.download;
    //由于plist文件中给的是图片的url,所以需要我们去下载
    //先去内存缓存中去找,如果内存缓存中有就直接取出来设置
    UIImage *image=[self.images objectForKey:item.icon];
    if (image) {
        cell.imageView.image=image;
        //如果内存缓存中没有就去沙盒(磁盘)里找,如果沙盒(磁盘)中有,就从沙盒(磁盘)中取出来设置,并且把图片保存到内存中
    }else{
        //获取沙盒路径
        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        //获取图片路径的最后一个节点
        NSString *imagePath=[item.icon lastPathComponent];
        //拼接路径获取图片的全路径
        NSString *fullPath=[caches stringByAppendingPathComponent:imagePath];
        //从磁盘中试着取数据
        NSData *data=[NSData dataWithContentsOfFile:fullPath];
        if (data) {
            UIImage *image=[UIImage imageWithData:data];
            cell.imageView.image=image;
            //如果磁盘中也没有找到图片数据,我们就先去操作字典中查找有没有这个图片的下载操作,如果有就等待下载完毕,如果没有就需要我们手动下载
        }else{

            //在图片下载完成之前设置一张占位图片,以防止cell重用引发的图片错乱问题
            cell.imageView.image=[UIImage imageNamed:@"xcode"];
            //试着去存储操作的字典里找当前的下载操作
            NSBlockOperation *download=[self.operations objectForKey:item.icon];
            //如果在字典中没有找到该操作,就需要我们手动下载了,由于下载图片是耗时操作,因此需要开启子线程下载
            if (download==nil) {
                //封装操作
                NSBlockOperation *download=[NSBlockOperation blockOperationWithBlock:^{
                    //获取图片的url
                    NSURL *url=[NSURL URLWithString:item.icon];
                    //根据图片的url将图片的二进制数据下载到本地
                    NSData *data=[NSData dataWithContentsOfURL:url];
                    //根据二进制数据生成一张图片
                    UIImage *image=[UIImage imageWithData:data];
                    //如果没有得到图片,直接返回,防止在设置图片的时候程序崩溃
                    if (image==nil) {
                        return ;
                    }
                    //将图片保存一份到内存中
                    [self.images setObject:image forKey:item.icon];
                    //将图片的二进制数据保存一份到磁盘中
                    [data writeToFile:fullPath atomically:YES];
                    //在主队列中设置图片
                    [[NSOperationQueue mainQueue]addOperationWithBlock:^{
                        //刷新表格
                        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    }];

                }];
                //将操作添加到队列中
                [self.queue addOperation:download];
                //将下载操作添加到缓存中一份,防止重复创建同一个操作
                [self.operations setObject:download forKey:item.icon];
            }else{
                //当在存储操作的字典里找到了当前的操作就会来到这个方法
                //在这里面不需要做任何操作,只需要等着图片加载完毕后显示即可
            }

        }

    }
    //返回当前的cell
    return cell;
}
//发生内存警告时的处理
-(void)didReceiveMemoryWarning{
    //清除图片缓存
    [self.images removeAllObjects];
    //取消所有的任务
    [self.queue cancelAllOperations];
}
@end

模型WJCellItem如下:

#import <Foundation/Foundation.h>

@interface WJCellItem : NSObject
@property (nonatomic,copy)NSString *name;
@property (nonatomic,copy)NSString *icon;
@property (nonatomic,copy)NSString *download;

+(instancetype)cellItemWithDict:(NSDictionary*)dict;
@end

#import "WJCellItem.h"

@implementation WJCellItem
+(instancetype)cellItemWithDict:(NSDictionary *)dict{
    WJCellItem *item=[[self alloc]init];
    [item setValuesForKeysWithDictionary:dict];
    return item;
}
@end

 

人已赞赏
iOS文章

移动开发中的 Web:WebView、WebKit、JSCore、Web 优化、热修复、跨平台、Native、Hybrid……

2019-10-24 13:20:07

iOS文章

iOS 使用Instruments的工具小结

2019-10-24 14:11:07

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索