IOS-多线程(NSOperation)
一、基础用法
//
// ViewController.m
// IOS_0120_NSOperation
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "ViewController.h" @interface ViewController ()<UITableViewDelegate> @property (nonatomic, strong) UIImageView *imageView; @end @implementation ViewController
/*
一、简介
1.NSOperation的作用
配合使用NSOperation和NSOperationQueue也能实现多线程编程 2.NSOperation和NSOperationQueue实现多线程的具体步骤
1>先将需要执行的操作封装到一个NSOperation对象中
2>然后将NSOperation对象添加到NSOperationQueue中
3>系统会自动将NSOperationQueue中的NSOperation取出来
4>将取出的NSOperation封装的操作放到一条新线程中执行 二、NSOperation的子类
1.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类 2.使用NSOperation子类的方式有3种
1>NSInvocationOperation
2>NSBlockOperation
3>自定义子类继承NSOperation,实现内部相应的方法 三、具体使用
1.NSInvocationOperation
1>创建NSInvocationOperation对象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg; 2>调用start方法开始执行操作
- (void)start;
一旦执行操作,就会调用target的sel方法 3>注意
默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作 2.NSBlockOperation
1>创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block; 2>通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block; 3>注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作 三、NSOperationQueue
1.NSOperationQueue的作用
NSOperation可以调用start方法来执行任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作 2.添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block; 四、最大并发数
1.什么是并发数
同时执行的任务数
比如,同时开3个线程执行3个任务,并发数就是3 2.最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt; 五、队列的取消、暂停、恢复
取消队列的所有操作
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作 暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended; 六、操作优先级
1.设置NSOperation在queue中的优先级,可以改变操作的执行优先级
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p; 2.优先级的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8 七、操作的监听
1.可以监听一个操作的执行完毕
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block; 八、操作的依赖
NSOperation之间可以设置依赖来保证执行顺序
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA]; // 操作B依赖于操作A
可以在不同queue的NSOperation之间创建依赖关系 注意:不能相互依赖 比如A依赖B,B依赖A 九、第三方框架的使用建议
1.用第三方框架的目的
1> 开发效率:快速开发,人家封装好的一行代码顶自己写的N行
2> 为了使用这个功能最牛逼的实现 2.第三方框架过多,很多坏处(忽略不计)
1> 管理、升级、更新
2> 第三方框架有BUG,等待作者解决
3> 第三方框架的作者不幸去世、停止更新(潜在的BUG无人解决)
4> 感觉:自己好水 3.比如
流媒体:播放在线视频、音频(边下载边播放)
非常了解音频、视频文件的格式
每一种视频都有自己的解码方式(C\C++) 4.总结
1> 站在巨人的肩膀上编程
2> 没有关系,使劲用那么比较稳定的第三方框架 十、SDWebImage
1.什么是SDWebImage
iOS中著名的牛逼的网络图片处理框架
包含的功能:图片下载、图片缓存、下载进度监听、gif处理等等
用法极其简单,功能十分强大,大大提高了网络图片的处理效率
国内超过90%的iOS项目都有它的影子
2.项目地址
https://github.com/rs/SDWebImage 1> 常用方法
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; 2> 内存处理:当app接收到内存警告时
当app接收到内存警告
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
SDWebImageManager *mgr = [SDWebImageManager sharedManager]; // 1.取消正在下载的操作
[mgr cancelAll]; // 2.清除内存缓存
[mgr.imageCache clearMemory];
}
3> SDWebImageOptions
* SDWebImageRetryFailed : 下载失败后,会自动重新下载
* SDWebImageLowPriority : 当正在进行UI交互时,自动暂停内部的一些下载操作
* SDWebImageRetryFailed | SDWebImageLowPriority : 拥有上面2个功能 十一、自定义NSOperation
自定义NSOperation的步骤很简单
重写- (void)main方法,在里面实现想执行的任务 重写- (void)main方法的注意点
自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应 */ - (void)viewDidLoad {
[super viewDidLoad]; // [self useNSInvocationOperation];
// [self useBaseNSBlockOperation];
// [self useNSBlockOperation];
// [self useNSOperationQueue];
// [self useAddDependency]; self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(, , , )];
[self.view addSubview:self.imageView];
[self communicate]; } #pragma mark - 通讯
- (void)communicate
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//取消队列所有操作
// [queue cancelAllOperations];
// NSLog(@"didCancelAllOperations");
//暂停队列
[queue setSuspended:YES];
//恢复队列
[queue setSuspended:NO];
//异步下载图片
[queue addOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://images.haiwainet.cn/2016/0113/20160113015030150.jpg"];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//回到主线程,显示图片
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
} - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// [queue setSuspended:YES]; //暂停队列中所有任务
} - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
// [queue setSuspended:NO]; //恢复队列中所有任务
} #pragma mark - 依赖
- (void)useAddDependency
{
/*三个异步执行操作:操作C依赖于操作B,操作B依赖于操作A*/ //创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"A1--------%@",[NSThread currentThread]);
}];
[operationA addExecutionBlock:^{
NSLog(@"A2--------%@",[NSThread currentThread]);
}];
[operationA setCompletionBlock:^{
NSLog(@"依赖于A--------%@",[NSThread currentThread]); }];
NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"B--------%@",[NSThread currentThread]);
}];
NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"C--------%@",[NSThread currentThread]);
}];
//设置依赖
[operationB addDependency:operationA];
[operationC addDependency:operationB]; [queue addOperation:operationA];
[queue addOperation:operationB];
[queue addOperation:operationC];
} #pragma mark - 队列中直接添加任务
- (void)useNSOperationQueue
{
//1.创建operation的时候,添加一个任务
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
}]; //2.创建队列(非主队列)会自动异步执行任务,并发
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //3.设置最大并发数
queue.maxConcurrentOperationCount = ; //4.添加操作到队列中
[queue addOperation:operation1];
[queue addOperation:operation2]; [queue addOperationWithBlock:^{
NSLog(@"--------下载图片3--------%@",[NSThread currentThread]);
}];
} #pragma mark - 多操作添加到队列
- (void)useNSBlockOperation
{
//创建operation的时候,添加一个任务
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
}];
//创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//主队列
// NSOperationQueue *queue = [NSOperationQueue mainQueue];
//添加操作到队列中
[queue addOperation:operation1];
[queue addOperation:operation2]; //[operation start];
} #pragma mark - NSBlockOperation
- (void)useBaseNSBlockOperation
{
//创建operation的时候,添加一个任务
// NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
// }]; NSBlockOperation *operation = [[NSBlockOperation alloc] init];
//操作中添加任务
[operation addExecutionBlock:^{
NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"--------下载图片3--------%@",[NSThread currentThread]);
}]; //任务大于1,才会异步执行
[operation start];
} #pragma mark - NSInvocationOperation
- (void)useNSInvocationOperation
{
//创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//创建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; //opreation直接调用start,是同步执行(在当前线程执行操作)
//[operation start]; //添加操作到队列中,会自动异步执行
[queue addOperation:operation];
} - (void)download
{
NSLog(@"download-------%@",[NSThread currentThread]);
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end
二、防止重复下载,与沙盒缓存
//
// BWApp.h
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import <Foundation/Foundation.h> @interface BWApp : NSObject @property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *download;
@property (nonatomic, copy) NSString *icon; + (instancetype)appWithDict:(NSDictionary *)dict; @end //
// BWApp.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWApp.h" @implementation BWApp + (instancetype)appWithDict:(NSDictionary *)dict
{
BWApp *app = [[self alloc] init];
[app setValuesForKeysWithDictionary:dict];
return app;
} @end
//
// BWTableViewController.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWTableViewController.h"
#import "BWApp.h" #define appImageCachesPath(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]] @interface BWTableViewController () //所有应用数据
@property (nonatomic, strong) NSMutableArray *appsArray;
//存放所有下载操作的队列
@property (nonatomic, strong) NSOperationQueue *queue;
//存放所有下载操作(url是key,operation对象是value)
@property (nonatomic, strong) NSMutableDictionary *operationDict;
//缓存图片
@property (nonatomic, strong) NSMutableDictionary *imageDict; @end @implementation BWTableViewController #pragma mark - 懒加载
- (NSMutableArray *)appsArray
{
if (!_appsArray) {
NSMutableArray *appArr = [[NSMutableArray alloc] init]; NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; for (NSDictionary *dict in dictArr) { BWApp *app = [BWApp appWithDict:dict];
[appArr addObject:app];
}
_appsArray = appArr;
}
return _appsArray;
} - (NSOperationQueue *)queue
{
if (!_queue) {
_queue = [[NSOperationQueue alloc] init];
}
return _queue;
} - (NSMutableDictionary *)operationDict
{
if (!_operationDict) {
_operationDict = [[NSMutableDictionary alloc] init];
}
return _operationDict;
} - (NSMutableDictionary *)imageDict
{
if (!_imageDict) {
_imageDict = [[NSMutableDictionary alloc] init];
}
return _imageDict;
} #pragma mark - 初始化
- (void)viewDidLoad {
[super viewDidLoad]; } - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning]; //移除所有下载操作
[self.queue cancelAllOperations];
[self.operationDict removeAllObjects];
//移除所有图片缓存
[self.imageDict removeAllObjects];
} #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.appsArray.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"cellID"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
//取出模型
BWApp *app = [self.appsArray objectAtIndex:indexPath.row]; cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download; //先从imageDict缓存中取出图片url对应的image
UIImage *image = self.imageDict[app.icon]; if (image) { //说明图片已经下载成功过
cell.imageView.image = image;
}
else //说明图片未下载(没有缓存)
{
//获取caches路径,拼接文件路径
NSString *filePath = appImageCachesPath(app.icon); NSData *data = [NSData dataWithContentsOfFile:filePath]; if (data) { //沙盒中存在这个图片
cell.imageView.image = [UIImage imageWithData:data];
}
else{
//显示占位图片
cell.imageView.image = [UIImage imageNamed:@"placeholder"];
} [self download:app.icon andIndexPath:indexPath];
}
return cell;
} - (void)download:(NSString *)imageUrl andIndexPath:(NSIndexPath *)indexPath
{
//取出当前图片对应的下载操作(operation对象)
NSBlockOperation *operation = self.operationDict[imageUrl]; if (operation) return; // __weak BWTableViewController *vc = self;
__weak typeof(self) appVC = self; //创建操作,下载图片
operation = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:imageUrl];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data]; //回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ //判断图片是否存在
if (image) {
//存放图片到字典中
appVC.imageDict[imageUrl] = image;
#warning 沙盒缓存
//将图片存入沙盒之中 UIImage --> NSData --> File(文件)
NSData *data = UIImagePNGRepresentation(image); // //获取caches路径
// NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//
// //拼接文件路径
// NSString *fileName = [imageUrl lastPathComponent];
// NSString *filePath = [cachesPath stringByAppendingPathComponent:fileName]; //写入缓存
[data writeToFile:appImageCachesPath(imageUrl) atomically:YES]; //UIImageJPEGRepresentation(UIImage * _Nonnull image, CGFloat compressionQuality)
}
//从字典中移除下载操作
[appVC.operationDict removeObjectForKey:imageUrl];
//刷新表格
//[self.tableView reloadData];
[appVC.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
}];
//添加操作到队列中
[appVC.queue addOperation:operation];
//添加操作到字典中(为了解决重复下载)
appVC.operationDict[imageUrl] = operation;
}
//保证图片只下载过一次
//当用户开始拖拽表格时
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//暂停下载
[self.queue setSuspended:YES];
}
//用户停止拖拽表格时
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
//恢复下载
[self.queue setSuspended:NO];
} @end
三、自定义NSOperation
//
// BWApp.h
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import <Foundation/Foundation.h> @interface BWApp : NSObject @property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *download;
@property (nonatomic, copy) NSString *icon; + (instancetype)appWithDict:(NSDictionary *)dict; @end //
// BWApp.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWApp.h" @implementation BWApp + (instancetype)appWithDict:(NSDictionary *)dict
{
BWApp *app = [[self alloc] init];
[app setValuesForKeysWithDictionary:dict];
return app;
} @end
//
// BWDownloadOperation.h
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/21.
// Copyright © 2016年 博文科技. All rights reserved.
// #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> @class BWDownloadOperation; @protocol BWDownloadOperationDelegate <NSObject> @optional
- (void)downloadOperation:(BWDownloadOperation *)operation didFinishDownload:(UIImage *)image; @end @interface BWDownloadOperation : NSOperation @property (nonatomic, copy) NSString *imageUrl;
@property (nonatomic, strong) NSIndexPath *indexPath; @property (nonatomic, weak) id<BWDownloadOperationDelegate> delegate; @end //
// BWDownloadOperation.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/21.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWDownloadOperation.h" @implementation BWDownloadOperation - (void)main
{
@autoreleasepool { if (self.isCancelled) return; //创建操作,下载图片
NSURL *url = [NSURL URLWithString:self.imageUrl];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data]; if (self.isCancelled) return; //回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {
[self.delegate downloadOperation:self didFinishDownload:image];
}
}];
}
}
@end
//
// BWTableViewController.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWTableViewController.h"
#import "BWApp.h"
#import "BWDownloadOperation.h" #define appImageCachesPath(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]] @interface BWTableViewController ()<BWDownloadOperationDelegate> //所有应用数据
@property (nonatomic, strong) NSMutableArray *appsArray;
//存放所有下载操作的队列
@property (nonatomic, strong) NSOperationQueue *queue;
//存放所有下载操作(url是key,operation对象是value)
@property (nonatomic, strong) NSMutableDictionary *operationDict;
//缓存图片
@property (nonatomic, strong) NSMutableDictionary *imageDict; @end @implementation BWTableViewController #pragma mark - 懒加载
- (NSMutableArray *)appsArray
{
if (!_appsArray) {
NSMutableArray *appArr = [[NSMutableArray alloc] init]; NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; for (NSDictionary *dict in dictArr) { BWApp *app = [BWApp appWithDict:dict];
[appArr addObject:app];
}
_appsArray = appArr;
}
return _appsArray;
} - (NSOperationQueue *)queue
{
if (!_queue) {
_queue = [[NSOperationQueue alloc] init];
}
return _queue;
} - (NSMutableDictionary *)operationDict
{
if (!_operationDict) {
_operationDict = [[NSMutableDictionary alloc] init];
}
return _operationDict;
} - (NSMutableDictionary *)imageDict
{
if (!_imageDict) {
_imageDict = [[NSMutableDictionary alloc] init];
}
return _imageDict;
} #pragma mark - 初始化
- (void)viewDidLoad {
[super viewDidLoad]; } - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning]; //移除所有下载操作
[self.queue cancelAllOperations];
[self.operationDict removeAllObjects];
//移除所有图片缓存
[self.imageDict removeAllObjects];
} #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.appsArray.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"cellID"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
//取出模型
BWApp *app = [self.appsArray objectAtIndex:indexPath.row]; cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download; //先从imageDict缓存中取出图片url对应的image
UIImage *image = self.imageDict[app.icon]; if (image) { //说明图片已经下载成功过
cell.imageView.image = image;
}
else //说明图片未下载(没有缓存)
{
//获取caches路径,拼接文件路径
NSString *filePath = appImageCachesPath(app.icon); NSData *data = [NSData dataWithContentsOfFile:filePath]; if (data) { //沙盒中存在这个图片
cell.imageView.image = [UIImage imageWithData:data];
}
else{
//显示占位图片
cell.imageView.image = [UIImage imageNamed:@"placeholder"];
} [self download:app.icon andIndexPath:indexPath];
}
return cell;
} - (void)download:(NSString *)imageUrl andIndexPath:(NSIndexPath *)indexPath
{
//取出当前图片对应的下载操作(operation对象)
BWDownloadOperation *operation = self.operationDict[imageUrl]; if (operation) return; //创建操作下载图片
operation = [[BWDownloadOperation alloc] init];
operation.imageUrl = imageUrl;
operation.indexPath = indexPath; //设置代理
operation.delegate = self; //添加操作到队列中
[self.queue addOperation:operation]; //添加操作到字典中(为了解决重复下载)
self.operationDict[imageUrl] = operation; } #pragma mark - 下载代理方法 - (void)downloadOperation:(BWDownloadOperation *)operation didFinishDownload:(UIImage *)image
{ //UIImageJPEGRepresentation(<#UIImage * _Nonnull image#>, <#CGFloat compressionQuality#>) //判断图片是否存在
if (image) {
//存放图片到字典中
self.imageDict[operation.imageUrl] = image; #warning 沙盒缓存
//将图片存入沙盒之中 UIImage --> NSData --> File(文件)
NSData *data = UIImagePNGRepresentation(image); //写入缓存
[data writeToFile:appImageCachesPath(operation.imageUrl) atomically:YES]; }
//从字典中移除下载操作(防止operationDict的下载操作越来越大,保证下载失败后能重新下载)
[self.operationDict removeObjectForKey:operation.imageUrl];
//刷新表格
//[self.tableView reloadData];
[self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];
} //保证图片只下载过一次
//当用户开始拖拽表格时
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//暂停下载
[self.queue setSuspended:YES];
}
//用户停止拖拽表格时
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
//恢复下载
[self.queue setSuspended:NO];
} @end
四、SDWebImage
//
// BWApp.h
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import <Foundation/Foundation.h> @interface BWApp : NSObject @property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *download;
@property (nonatomic, copy) NSString *icon; + (instancetype)appWithDict:(NSDictionary *)dict; @end //
// BWApp.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWApp.h" @implementation BWApp + (instancetype)appWithDict:(NSDictionary *)dict
{
BWApp *app = [[self alloc] init];
[app setValuesForKeysWithDictionary:dict];
return app;
} @end
//
// BWTableViewController.m
// IOS_0120_NSOperation防止重复下载
//
// Created by ma c on 16/1/20.
// Copyright © 2016年 博文科技. All rights reserved.
// #import "BWTableViewController.h"
#import "BWApp.h"
#import "UIImageView+WebCache.h" @interface BWTableViewController () //所有应用数据
@property (nonatomic, strong) NSMutableArray *appsArray; @end @implementation BWTableViewController #pragma mark - 懒加载
- (NSMutableArray *)appsArray
{
if (!_appsArray) {
NSMutableArray *appArr = [[NSMutableArray alloc] init]; NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:path]; for (NSDictionary *dict in dictArr) { BWApp *app = [BWApp appWithDict:dict];
[appArr addObject:app];
}
_appsArray = appArr;
}
return _appsArray;
} #pragma mark - 初始化
- (void)viewDidLoad {
[super viewDidLoad]; } - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
} #pragma mark - Table view data source //- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//
// return 1;
//} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // return self.appsArray.count;
return ;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellID = @"cellID"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
//取出模型
BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
//设置基本信息
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download; //下载图片
// NSURL *url = [NSURL URLWithString:@"http://img.cnblogs.com/ad/not-to-stop-questioning.jpg"]; NSURL *url = [NSURL URLWithString:app.icon];
UIImage *image = [UIImage imageNamed:@"placeholder"];
// [cell.imageView sd_setImageWithURL:url placeholderImage:image]; SDWebImageOptions options = SDWebImageRetryFailed | SDWebImageLowPriority; [cell.imageView sd_setImageWithURL:url placeholderImage:image options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) { NSLog(@"下载进度:%f",(double)receivedSize / expectedSize); } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
NSLog(@"-----图片加载完毕-----%@",image);
}]; return cell;
} @end
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
SDWebImageManager *maneger = [SDWebImageManager sharedManager];
//1.取消正在下载的操作
[maneger cancelAll];
//2.清除内存缓存
[maneger.imageCache clearMemory];
maneger.imageCache.maxCacheAge = ***;
}
IOS-多线程(NSOperation)的更多相关文章
- iOS 多线程 NSOperation、NSOperationQueue
1. NSOperation.NSOperationQueue 简介 NSOperation.NSOperationQueue 是苹果提供给我们的一套多线程解决方案.实际上 NSOperation.N ...
- iOS多线程 NSOperation的用法
上一篇写了 GCD 的使用,接下来就了解一下 NSOperation ,NSOperation是苹果对 GCD 的 OC 版的一个封装,但是相对于GCD来说可控性更强,并且可以加入操作依赖. NSOp ...
- iOS多线程--NSOperation 浅显易懂
NSOperation是基于GCD的一套多线程实现方案,和GCD一样,线程的生命周期是由系统来自动管理的,不用像NSThread和Pthread一样让程序员手动管理.相对于GCD来说,它更加地面向对象 ...
- iOS多线程--NSOperation
NSOperation是基于GCD的一套多线程实现方案,和GCD一样,线程的生命周期是由系统来自动管理的,不用像NSThread和Pthread一样让程序员手动管理.相对于GCD来说,它更加地面向对象 ...
- iOS多线程---NSOperation介绍和使用
1. NSOperation实现多线程编程,需要和NSOperationQueue一起使用. (1)先将要执行的操作封装到NSOperation中 (2)将NSOperation对象添加到NSOpe ...
- IOS 多线程 NSOperation GCD
1.NSInvocationOperation NSInvocationOperation * op; NSOperationQueue * que = [[NSOperationQueuealloc ...
- iOS多线程---NSOperation的常用操作
1.最大并发数: - (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger) ...
- iOS多线程编程
废话不多说,直接上干货.先熟悉一下基本知识,然后讲一下常用的两种,NSOperation和GCD. 一.基础概念 进程: 狭义定义:进程是正在运行的程序的实例(an instance of a com ...
- iOS GCD NSOperation NSThread等多线程各种举例详解(拷贝)
2年多的iOS之路匆匆而过,期间也拜读来不少大神的博客,近来突然为自己一直做伸手党感到羞耻,是时候回馈社会.回想当年自己还是小白的时候,照着一些iOS多线程教程学,也只是照抄,只知其然.不知其所以然. ...
- iOS 多线程学习笔记 —— NSOperation
本文复制.参考自文章:iOS多线程编程之NSOperation和NSOperationQueue的使用 ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://b ...
随机推荐
- Linux环境下proc的配置c/c++操作数据库简单示例
在虚拟机上装了oracle11g数据库,原本想利用c/c++学习操作数据库.结果感觉摊上了一个大坑.从安装好oracle数据库到配置好proc的编译选项整整花了二天.但让我意识到自己自己几点薄弱:1. ...
- s3对象存储
bkstorages 模块帮助你在蓝鲸应用中使用多种文件存储服务作为后端,用于加速静态资源,管理用户上传文件. 自定静态文件 storage 如果通过修改配置文件满足不了你的需求,你随时可以通过继承 ...
- Worst Performing Queries
WITH TMP AS ( SELECT TOP 100 CAST(SUM(s.total_elapsed_time) / 1000000.0 AS DECIMAL(10, 2)) AS [Total ...
- ABP常见问题
System.Data.SqlClient.SqlException (0x80131904): 'OFFSET' 附近有语法错误 解决方案:最新的ABP默认支持的是sql2012以上的版本,对于之前 ...
- Java之父及Java诞生
来自为知笔记(Wiz)
- The adidas NMD Singapore is one of the brands top selling
Like pointed out, we've two adidas NMD Singapore releases using the first arriving Blue and Black as ...
- MDI QMdiArea 多文档区域
Qt下创建类似window平台的MDI多文档区域使用QMdiArea QMdiArea * mdiArea; mdiArea = new QMdiArea(this); //A widget 为win ...
- 78. Subsets(回溯)
Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The sol ...
- 11Qt样式表
Qt样式表 Qt样式表的思想很大程度上是来自原HTML的层叠式样式表(CSS),通过调用Qwdiget::setStyleSheet()或是Qapplication::setStyleSheet(), ...
- 497. Random Point in Non-overlapping Rectangles
1. 问题 给定一系列不重叠的矩形,在这些矩形中随机采样一个整数点. 2. 思路 (1)一个矩形的可采样点个数就相当于它的面积,可以先依次对每个矩形的面积累加存起来(相当于概率分布中的分布累积函数CD ...