一 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的处理逻辑