NSOperation 操作? 任务是对代码的封装, 操作是对任务的封装 --目的:就是可以随时的暂停/恢复/取消任务;
NSOperation 对GCD的封装. OC 运用起来更加方便. 抽象类. 车
NSOperation的使用:
<1> 操作直接调用 start方法,就是在当前线程执行(Block中封装的任务数大于1的情况除外).
<2> 就是将操作放在队列中.自动的帮我们开启线程,来执行操作.
两个子类:
NSInvocationOperation: 调用
? ? ?
1. NSOperation的两个子类的使用:
?// 创建一个NSOpertation的子类 NSInvocationOperation
? ?? NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self ? ?? ?????selector:@selector(longTimeOperation) object:nil];
? ? ?[op1 start]; ?//调用 ?开始任务 ?
? ? ? 不会开启线程。 ?在主线程中执行?
?NSBlockOperation:Block
? // 创建一个NSOpertation的子类 ?NSBlockOperation
??? NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
??????? // Block中封装操作.
??????? [self longTimeOperation];
??? }];
//?追加一个操作(任务).
??? [op2 addExecutionBlock:^{
??????? NSLog(@"下载图片1:%@",[NSThread currentThread]);
??? }];
? // 追加一个操作(任务).
??? [op2 addExecutionBlock:^{
??????? NSLog(@"下载图片2:%@",[NSThread currentThread]);
??? }];
// [op2 start];
?? // NSBlockOperation 直接调用start方法:
?? // 如果只有一个任务:在主线程中执行
?? // 如果有多个任务:会开启多条线程,在主线程中和子线程中都执行任务.
?? // 多个任务都是同时执行的.
??? // 操作完成之后的回调(异步的回调)
??? // 一般用的不多.
??? op2.completionBlock = ^{
??????? // 操作执行完毕的回调(什么时候操作执行完毕,我们并不知道)
??????? NSLog(@"操作1执行完毕%@",[NSThreadcurrentThread]);
??? };
? ?
?// 创建一个非队列: ?非主队列:非主队列存放的操作都在子主线程中执行.
??? NSOperationQueue *queue = [[NSOperationQueue alloc] init];
?// 获取一个主队列 ??主队列:主队列存放的操作在主线程中执行
??? NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
?// 使用:将操作添加到队列中
??? [queue? ?addOperation:op2];
??? [queue?addOperation:op1];
?// 将操作添加到队列中,会自动(开启线程)的异步执行操作.
? ? 任务增加到队列中。 就调用Operation里的main方法。 ?然后自动执行任务? ? ?
任务依赖
? ? [op1 addDependency:op2]; ?//等任务 op2 执行完后 在执行op1
??? [op2 addDependency: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 = [NSBlockOperation blockOperationWithBlock:^{
??????[wself longTimeOperation];
}];
? ? // 取消单个操作,一般也不用.
??? [op2 cancel];
??? // 暂停队列中的操作
??? [self.queue setSuspended:YES];
??? // 恢复队列中的操作
??? [self.queue setSuspended:NO];
??? // 取消所有操作,对于已经取消的操作,就永远取消了,不会再次开启
??? [self.queue cancelAllOperations];
// 自定义NSOperation; 线程间通讯
??? NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{
??????? // 执行的任务
??????????? UIImage *image = [selflongTimeOperation];
??????????? NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{
? ? ? ? ? ? ? self.imageView.image = image;
? ? ? ? ?? }];
? ? ? ? [[NSOperationQueue mainQueue] addOperation:op];
??? }];
下面都是自定义NSOperation方式
// 不同对象间的通讯
三种方式
? ? ? ?? 1.通知
1.>// 下载图片完成的时候?发送一个通知,将图片传递出去(通知中的参数是image) ?
[[NSNotificationCenter defaultCenter] postNotificationName:@"ITDownloadImageOperation" object:image];
2.>// 在需要用到内容的类 注册通知的接收者.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setUpImage:)?name:@"ITDownloadImageOperation" object:nil];
3.>// 通知传递的参数,永远是一个NSNotification; ? 注册通知时用到的方法
- (void)setUpImage:(NSNotification *)notify
{
??? // 回到主线程
??? dispatch_async(dispatch_get_main_queue(), ^{?
??????? NSLog(@"setUpImage%@",[NSThread currentThread]);
??????? // 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) downloadImageOperationBlock downBlock;
// 3. 设置Block中想要执行的内容;
// Block 只是一个块代码.Block中的内容什么时候执行,和定义其中的内容是分开进行的.
op.downBlock = ^(UIImage *image){
? ? // Block中想要执行的内容.
? ? self.imageView.image = image;
};
// 4. 在 main执行这个Block ?
-(void)main
{
??? @autoreleasepool {
// 在子线程下载图片
??????? UIImage *image = [self downloadImage];
?// 回到主线程
??????? [[NSOperationQueue mainQueue] 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中的内容是一个参数
??? [op setUpImageWithBlock:^(UIImage *image) {
??????? // 定义一个Block中执行的内容.
??????? self.imageView.image = image;
??? }];
? ? ?????// 6.调用block ?与上面第4步一样
?? 3.block 方法形式 传本身类 ? ?
? ? ? ? ? ? ? ?? ? ?些方法跟 传单个对象用法一模一样 只是在调用bolck时传self
? ? ? ? ? ? ? ? ? ??self.downBlock(image);
? ? ?? ? 在设置值的时候 用对象.某个对象
? ITDownloadOperationBlock *op = [[ITDownloadOperationBlockalloc] init];
? [op setUpImageWithBlock:^(ITDownloadOperationBlock *op) {
? ? ? self.imageView.image = op.image;
? }];? ? ?
? ?
?