NSOperation操作 任务是对代码的封装,操作是对任务的封装--目的:就是可以随时的暂停/恢复/取消任务;
NSOperation对GCD的封装. OC运用起来更加方便.抽象类.车
NSOperation的使用:
<1>操作直接调用start方法,就是在当前线程执行(Block中封装的任务数大于1的情况除外).
<2>就是将操作放在队列中.自动的帮我们开启线程,来执行操作.
两个子类:
NSInvocationOperation:调用
1.NSOperation的两个子类的使用:
//创建一个NSOpertation的子类NSInvocationOperation
NSInvocationOperation*op1 = [[NSInvocationOperationalloc]initWithTarget:self selector:@selector(longTimeOperation)object:nil];
[op1 start]; //调用 开始任务
不会开启线程。 在主线程中执行
NSBlockOperation:Block
//创建一个NSOpertation的子类 NSBlockOperation
NSBlockOperation*op2 = [NSBlockOperationblockOperationWithBlock:^{
// Block中封装操作.
[selflongTimeOperation];
}];
// 追加一个操作(任务).
[op2addExecutionBlock:^{
NSLog(@"下载图片1:%@",[NSThreadcurrentThread]);
}];
//追加一个操作(任务).
[op2addExecutionBlock:^{
NSLog(@"下载图片2:%@",[NSThreadcurrentThread]);
}];
// [op2 start];
// NSBlockOperation直接调用start方法:
//如果只有一个任务:在主线程中执行
//如果有多个任务:会开启多条线程,在主线程中和子线程中都执行任务.
//多个任务都是同时执行的.
//操作完成之后的回调(异步的回调)
//一般用的不多.
op2.completionBlock= ^{
//操作执行完毕的回调(什么时候操作执行完毕,我们并不知道)
NSLog(@"操作1执行完毕%@",[NSThreadcurrentThread]);
};
//创建一个非队列: 非主队列:非主队列存放的操作都在子主线程中执行.
NSOperationQueue*queue = [[NSOperationQueuealloc]init];
//获取一个主队列 主队列:主队列存放的操作在主线程中执行
NSOperationQueue*mainQueue = [NSOperationQueuemainQueue];
//使用:将操作添加到队列中
[queue addOperation:op2];
[queue addOperation:op1];
//将操作添加到队列中,会自动(开启线程)的异步执行操作.
任务增加到队列中。 就调用Operation里的main方法。 然后自动执行任务
任务依赖
[op1addDependency:op2]; //等任务 op2 执行完后 在执行op1
[op2addDependency:op3]; //等任务 op3 执行完后 在执行op2
这两句的效果是: op3最先执行 在op2 执行 最后执行 op1
高级操作:
一般情况下 队列都用懒加载的方法来实现
@PRoperty(nonatomic,strong)NSOperationQueue*queue;
//懒加载Queue
-(NSOperationQueue*)queue
{
if(!_queue) {
_queue= [[NSOperationQueuealloc]init];
//最大并发数为6 .
[_queuesetMaxConcurrentOperationCount:6];
}
return_queue;
}
在block中 用到self 都要用weak方式 否则会造循环引用问题
_weaktypeof(self) wself =self;
NSBlockOperation*op2 = [NSBlockOperationblockOperationWithBlock:^{
[wselflongTimeOperation];
}];
//取消单个操作,一般也不用.
[op2cancel];
//暂停队列中的操作
[self.queuesetSuspended:YES];
//恢复队列中的操作
[self.queuesetSuspended:NO];
//取消所有操作,对于已经取消的操作,就永远取消了,不会再次开启
[self.queuecancelAllOperations];
//自定义NSOperation;线程间通讯
NSBlockOperation*op = [NSBlockOperationblockOperationWithBlock:^{
//执行的任务
UIImage*image = [selflongTimeOperation];
NSBlockOperation*op = [NSBlockOperationblockOperationWithBlock:^{
self.imageView.image= image;
}];
[[NSOperationQueuemainQueue]addOperation:op];
}];
下面都是自定义NSOperation方式
//不同对象间的通讯
三种方式
1.通知
1.>// 下载图片完成的时候 发送一个通知,将图片传递出去(通知中的参数是image)
[[NSNotificationCenterdefaultCenter]postNotificationName:@"ITDownloadImageOperation"object:image];
2.>// 在需要用到内容的类注册通知的接收者.
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(setUpImage:) name:@"ITDownloadImageOperation"object:nil];
3.>//通知传递的参数,永远是一个NSNotification; 注册通知时用到的方法
- (void)setUpImage:(NSNotification*)notify
{
//回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"setUpImage%@",[NSThreadcurrentThread]);
// notify.object就是通知传递的对象.
//本次通知中,通知传递的对象就是这个操作
ITDownloadImageOperation*op = notify.object;
self.imageView.image= op.image;
});
}
2.代理
参考以前代理的写法 一模一样
3.block
// 1.定义一个block类型 参数为image
typedefvoid(^downloadImageOperationBlock)(UIImage*image);
// 2.定义一个Block的属性
@property(nonatomic,copy)downloadImageOperationBlockdownBlock;
// 3. 设置Block中想要执行的内容;
// Block只是一个块代码.Block中的内容什么时候执行,和定义其中的内容是分开进行的.
op.downBlock= ^(UIImage*image){
// Block中想要执行的内容.
self.imageView.image= image;
};
// 4. 在main执行这个Block
-(void)main
{
@autoreleasepool{
//在子线程下载图片
UIImage*image = [selfdownloadImage];
//回到主线程
[[NSOperationQueuemainQueue]addOperationWithBlock:^{
if(self.downBlock) {
self.downBlock(image);
NSLog(@"执行Block中的内容:设置图片");
}
}];
}
}
3.block 方法形式 传单个对象 如UIImage
前两步 跟上面一样
// 3.定义一个方法,负责传递Block
// (downloadImageOperationBlock)blk:把Block当做一个参数来传递
- (void)setUpImageWithBlock:(downloadImageOperationBlock)blk;
// 4.实现这个方法,self.downBlock赋值
-(void)setUpImageWithBlock:(downloadImageOperationBlock)blk
{
if(blk) {
//给self.downBlock赋值(Block内部执行的方法)
self.downBlock= blk;
}
}
// 5.Block中的内容是一个参数
[opsetUpImageWithBlock:^(UIImage*image) {
//定义一个Block中执行的内容.
self.imageView.image= image;
}];
// 6.调用block 与上面第4步一样
3.block 方法形式 传本身类
些方法跟 传单个对象用法一模一样 只是在调用bolck时传self
self.downBlock(image);
在设置值的时候 用对象.某个对象
ITDownloadOperationBlock*op = [[ITDownloadOperationBlockalloc]init];
[opsetUpImageWithBlock:^(ITDownloadOperationBlock*op) {
self.imageView.image= op.image;
}];