NSOperation
1.简单说明
NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤:
(1)先将需要执行的操作封装到一个NSOperation对象中
(2)然后将NSOperation对象添加到NSOperationQueue中
(3)系统会⾃动将NSOperationQueue中的NSOperation取出来
(4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏
2.NSOperation的子类
NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类
使用NSOperation⼦类的方式有3种:
(1)NSInvocationOperation
(2)NSBlockOperation
(3)自定义子类继承NSOperation,实现内部相应的⽅法
一、并发数
(1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3
(2)最大并发数:同一时间最多只能执行的任务的个数。
(3)最⼤大并发数的相关⽅方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。
注意:num的值并不代表线程的个数,仅仅代表线程的ID。
提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。
二、队列的取消,暂停和恢复
(1)取消队列的所有操作
- (void)cancelAllOperations;
提⽰:也可以调用NSOperation的- (void)cancel⽅法取消单个操作
(2)暂停和恢复队列
(void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
(BOOL)isSuspended; //当前状态
(3)暂停和恢复的适用场合:在tableview界面,开线程下载远程的网络界面,对UI会有影响,使用户体验变差。那么这种情况,就可以设置在用户操作UI(如滚动屏幕)的时候,暂停队列(不是取消队列),停止滚动的时候,恢复队列。
三、操作优先级
(1)设置NSOperation在queue中的优先级,可以改变操作的执⾏优先级
- (NSOperationQueuePriority)queuePriority;
(void)setQueuePriority:(NSOperationQueuePriority)p;
(2)优先级的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
说明:优先级高的任务,调用的几率会更大。
四、操作依赖
(1)NSOperation之间可以设置依赖来保证执行顺序,⽐如一定要让操作A执行完后,才能执行操作B,可以像下面这么写
[operationB addDependency:operationA]; // 操作B依赖于操作
(2)可以在不同queue的NSOperation之间创建依赖关系
注意:不能循环依赖(不能A依赖于B,B又依赖于A)。
(1).NSInvocationOperation子类
#import "FirstViewController.h"
@interface FirstViewController ()
@end
@implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// NSOperation:抽象类,不具备封装功能
//创建操作对象,封装要执行的任务
// NSInvocationOperation 封装操作
NSInvocationOperation *operation =
[[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(test)
object:nil];
//执行操作
[operation start];
}
- (void)test {
NSLog(@"--test--%@--", [NSThread currentThread]);
}
@end
(2).NSBlockOperation子类
#import "SecondViewController.h"
@interface SecondViewController ()
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//创建NSBlockOperation操作对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation------%@", [NSThread currentThread]);
}];
//添加操作
[operation addExecutionBlock:^{
NSLog(@"NSBlockOperation1------%@", [NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"NSBlockOperation2------%@", [NSThread currentThread]);
}];
//开启执行操作
[operation start];
}
@end
(3).自定义子类继承NSOperation,实现内部相应的⽅法
#import <UIKit/UIKit.h>
@interface DownLoadOperation : NSOperation
@property (nonatomic, copy) NSString *urlString;
@property (nonatomic, copy) void (^finishBlock) (UIImage *image);
@end
#import "DownLoadOperation.h"
@implementation DownLoadOperation
#import "DownLoadOperation.h"
@implementation DownLoadOperation
- (void)main {
//必须要添加自动释放池
@autoreleasepool {
NSURL *url = [NSURL URLWithString:self.urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *icon = [UIImage imageWithData:imageData];
if (self.finishBlock) {
self.finishBlock(icon);
}
}
}
@end
@end
#import "DownLoadOperation.h"
#import "ViewController.h"
@interface ViewController ()
@property(weak, nonatomic) IBOutlet UIImageView *iconVIew;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self loadImage];
}
- (void)loadImage {
NSString *imageUrl =
@"http://pica.nipic.com/2007-11-09/200711912453162_2.jpg";
DownLoadOperation *op = [[DownLoadOperation alloc] init];
op.urlString = imageUrl;
__weak typeof(self) weakSelf = self;
// __weak ViewController *weakSelf = self;
op.finishBlock = ^(UIImage *image) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//主线程刷新 UI
weakSelf.iconVIew.image = image;
}];
};
//主线程回调
/**
* 使用NSOperationQueue 只能获取两种队列
* 1.[[NSOperationQueue alloc] init]一种自己创建的并发队列
* 2.[NSOperationQueue mainQueue] 可以获得主队列,这是apple
* 提供的快速回到主队列方法
*/
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//在将操作添加到队列中,就会执行操作的main 方法
[queue addOperation:op];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end