您的位置:首页 > 运维架构

解析SDWebImage框架和RunLoop

2016-03-19 01:51 309 查看

一 SDWebImage下载图片的基本操作

1 下载图片并显示(内存缓存&磁盘缓存)

/*
第一个参数:图片的url地址
第二个参数:设置的占位图片
*/
[self.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://img3.a0bi.com/upload/ttq/20150125/1422148697268_middle.jpg"] placeholderImage:[UIImage imageNamed:@"Snip20160112_4"]];


2 下载图片显示并计算下载进度

2.1 代码实现内存缓存,磁盘缓存和下载进度

//下载图片&设置显示图片&内存缓存&磁盘缓存
- (void)download
{
//参数一:下载图片的路径
//参数二:占位图片
//参数三:下载选项
//参数四:进度回调
//参数五:完成回调
[self.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://i.ce.cn/fashion/news/201603/04/W020160304475595612586.jpg"] placeholderImage:[UIImage imageNamed:@"/Users/xiaofeng/Desktop/Snip20160316_1.png"] options:SDWebImageLowPriority | SDWebImageCacheMemoryOnly progress:^(NSInteger receivedSize, NSInteger expectedSize) {

NSLog(@"%f",(float)receivedSize / expectedSize);

} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {

NSLog(@"%@---%@",error,[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES) lastObject]);
//判断缓存方式
switch (cacheType) {
case SDImageCacheTypeNone:
NSLog(@"直接下载的图片-----");
break;
case SDImageCacheTypeDisk:
NSLog(@"磁盘缓存图片-----");
break;
case SDImageCacheTypeMemory:
NSLog(@"内存缓存图片-----");
break;

default:
break;
}

}];
}


3 下载图片不显示并且监听下载进度(用框架中的管理者模块)

3.1 代码实现内存缓存,磁盘缓存和下载进度

//下载图片&内存缓存&磁盘缓存
- (void)download2
{
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:@"http://img3.a0bi.com/upload/ttq/20150125/1422148697268_middle.jpg"] options:kNilOptions progress:^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"%f",(float)receivedSize / expectedSize);
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
NSLog(@"%@-----%@",error,[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES) lastObject]);

if (error == nil) {
self.imageView.image = image;
}
}];
}


4 下载图片不显示并且不做任何的处理

4.1 注意:完成后回调是在子线程中处理的,刷新UI显示图片是在主线程中进行的

- (void)download3
{
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:@"http://image.zjg.js.cn/upload/editor/2014-7-1/2014711345189400th1b.jpg"] options:SDWebImageDownloaderLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize) {

NSLog(@"%f",(float)receivedSize / expectedSize);
NSLog(@"1-------%@",[NSThread currentThread]);

} completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {

NSLog(@"2-------%@",[NSThread currentThread]);
//下载图片completed是在子线程中处理的,那么需要到主线程中刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"3--------%@",[NSThread currentThread]);
self.imageView.image = image;
});

}];
}


5 播放Gif图片

//下载动态图
- (void)download5
{
NSURL *url = [NSURL URLWithString:@"http://img4q.duitang.com/uploads/item/201501/26/20150126180214_mAmSH.thumb.224_0.gif"];
NSData *data = [NSData dataWithContentsOfURL:url];
self.imageView.image = [UIImage sd_animatedGIFWithData:data];
}


6 接收到内存发出来的警告,如何处理?

6.1 取消当前正在进行的所有的下载操作

[[SDWebImageManager sharedManager] cancelAll];


6.2 清除缓存数据

[[SDWebImageManager sharedManager].imageCache cleanDisk];
[[SDWebImageManager sharedManager].imageCache clearMemory];


6.2.1 两者清除区别:

1> cleanDisk:删除过期的文件数据,计算当前未过期的已经下载的文件数据的大小,如果发现该数据大小大于我们设置的最大缓存数据大小,那么程序内部会按照按文件数据缓存的时间从远到近删除,知道小于最大缓存数据为止。
2> clearMemory:直接删除文件,重新创建新的文件夹


7 SDWebImage框架内部的具体实现细节

7.1 判断当前图片类型:只判断图片二进制数据的第一个字节

7.2 默认的缓存周期:1周

7.3 缓存策略:默认情况下既做内存缓存又做磁盘缓存,下载图片前先检查内存缓存,再检查磁盘缓存

7.4 缓存的实现方式:采用了苹果推出的专门用来处理缓存的类NSCache

7.5 框架内部允许的最大并发数:6

7.6 对系统内存警告的处理方式:框架内部监听系统内存警告的通知,当发生后移除内存缓存中的所有对象

7.7 下载队列中对多个图片任务的处理方式:提供了FIFO和LIFO两种方式,默认为FIFO

7.8 如何下载图片:采用NSURLConnection发送网络请求,在其代理方法中接收数据并处理进度回调等工作

7.9 请求超时的设定:15秒

7.10 磁盘缓存图片的命名:以该图片的URL进行MD5散列加密【echo -n “url” |MD5】

7.11 缓存路径:~/Library/Caches/default/com.hackemist.SDWebImageCache.default

7.12 key—–>URL(如何优化):用黑名单(当一个URL请求失败后,会被添加到黑名单,可以有效的防止一个错误的URL被多次尝试下载)

二 RunLoop基本使用

1 RunLoop字面意思:跑圈

2 RunLoop实际含义:一个APP能一直运行的关键

3 注意:

(1)如果没有RunLoop,那么程序一启动就会退出,什么事情都做不了。

(2)如果有了RunLoop,那么相当于在内部有一个死循环,能够保证程序的持续运行

(3)main函数中的RunLoop

——a 在UIApplication函数内部就启动了一个RunLoop,该函数返回一个int类型的值

——b 这个默认启动的RunLoop是跟主线程相关联的

4 RunLoop与线程的关系

(1)RunLoop和线程的关系:一个RunLoop对应着一条唯一的线程

——问题:如何让子线程不死

——回答:给这条子线程开启一个RunLoop

(2)RunLoop的创建:主线程RunLoop已经创建好了,子线程的RunLoop需要手动创建

(3)RunLoop的生命周期:在第一次获取时创建,在线程结束时销毁

三 获取RunLoop对象

1 第一种类型的RunLoop:

1.1 获得当前线程对应的RunLoop

NSRunLoop *run = [NSRunLoop currentRunLoop];


1.2 获取主线程的RunLoop

NSRunLoop *run1 = [NSRunLoop mainRunLoop];


2 第二种类型的RunLoop

2.1 当前的RunLoop

CFRunLoopRef current = CFRunLoopGetCurrent();


2.2 获取主线程对应的RunLoop

CFRunLoopRef main = CFRunLoopGetMain();


3 注意点:

3.1 注意点:开一个子线程创建runloop,不是通过alloc init方法创建,而是直接通过调用currentRunLoop方法来创建,它本身是一个懒加载的。

3.2 在子线程中,如果不主动获取Runloop的话,那么子线程内部是不会创建Runloop的。可以下载CFRunloopRef的源码,搜索_CFRunloopGet0,查看代码。

3.3 Runloop对象是利用字典来进行存储,而且key是对应的线程Value为该线程对应的Runloop。

四 理解三张关于RunLoop的运行图

第一张图:RunLoop的处理逻辑





以上的描述是对第一张图的RunLoop运行描述

第二张图:通俗易懂图



特别说明:两张图其实描述的都差不多,只有第七点做了判断.

第三张图:mode(模式图)



解析第三张图:

注意: Runloop要想跑起来,它的内部必须要有一个mode,这个mode里面必须有source\observer\timer,至少要有其中的一个。

01. CFRunloopModeRef代表着Runloop的运行模式

02. 一个Runloop中可以有多个mode,一个mode里面又可以有多个source\observer\timer等等

03. 每次runloop启动的时候,只能指定一个mode,这个mode被称为该Runloop的当前mode

04. 如果需要切换mode,只能先退出当前Runloop,再重新指定一个mode进入

05. 这样做主要是为了分割不同组的定时器等,让他们相互之间不受影响

06. 系统默认注册了5个mode

—–a. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行

—–b. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

—–c. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用

—–d. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到

—–e. kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode

五 总结

注意: 以上就是对SDWebImage框架和RunLoop的基本使用,还有很多不足的地方,我会找时间补上,大家有什么问题,可以给我留言,谢谢!!!!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: