使用NSOperation和NSOperationQueue进行多线程开发,只要将一个NSOperation(实际开发中需要使用其子类 NSInvocationOperation,NSBlockOperation)放到NSOperationQueue这个队列中线程就会依次启动。NSOPerationQUeue负责管理,执行所有的NSOPeration。在这个过程中可以更加容易管理线程的总数和控制线程之间的依赖关系。
NSInvocationOperation
首先使用NSInvocationOperation进行一张图片的加载演示,整个过程就是:创建一个操作,在这个操作中指定调用方法和参数,然后加入到操作队列。操作队列管理和执行所有的NSOperation。
- (void)loadImageWithThread{ //创建一个调用操作 NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImage) object:nil]; //创建玩一个NSInvocationOPeration对象并不会调用 它由一个start方法启动操作 但是要注意 调用start方法会在主线程之中调用。一般不会这么操作,而是添加到NSOPerationQueue中。 //创建一个操作队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //注意添加到操作队列中后 队列会启动一个线程执行操作 [queue addOperation:invocationOperation]; }
NSBlockOperation
下面使用NSBlockOperation创建多哥线程加载图片
点击一个按钮开辟多个线程 完成多个图片的加载过程:
#pragma mark - 多线程下载图片 - (void)loadImageWithThread{ int count = ROW_COUNT * COLUMN_COUNT; //创建操作队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //最大并发线程的数量 queue.maxConcurrentOperationCount = 5; for (int i = 0; i < count; i ++) { NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:i]]; }]; [queue addOperation:operation]; //方法二 [queue addOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:i]]; }]; } } #pragma mark -下载图片 - (void)loadImage:(NSNumber *)index{ //请求数据 //currentThread方法可以取得当前操作线程 NSLog(@"current thread:%@",[NSThread currentThread]); int i = (int)[index integerValue]; NSData *Data = [self requestData:i]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self updateImage:Data andIndex:i]; }]; } - (void)updateImage:(NSData *)imageData andIndex:(int) index{ UIImage *image = [UIImage imageWithData:imageData]; UIImageView *imageView = _imageViews[index]; imageView.image = image; } - (NSData *)requestData:(int)i{ @autoreleasepool { if (i != (ROW_COUNT*COLUMN_COUNT-1)) { [NSThread sleepForTimeInterval:2.0]; } NSURL *url = [NSURL URLWithString:@"http://images.apple.com/iphone-6/overview/images/biggest_right_large.png"]; NSData *data = [NSData dataWithContentsOfURL:url]; return data; } }
注意:
1.使用NSBlockOperation方法 所有操作不必单独定义方法,同时可以传递多个参数
2.调用多线程队列的addOperationWithBlock:方法进行UI更新 不用在定义一个实体对象,因为可以传递多个参数
3.使用NSOperation进行多线程开发可以设置最大并发线程。有效的对线程进行了控制
其实使用NSOPeration和NSoperationQueue进行多线程开发最主要的是可以控制最大并发线程数和可以很方便的控制各个线程的执行顺序。上面的例子中已经设置了最大并发线程数。下面我们来看一看控制线程执行的顺序。每个NSoperation都可以添加设置依赖。假设操作A依赖与操作B。线程操作队列就会先执行B在执行A。
#pragma mark - 多线程下载图片 - (void)loadImageWithThread{ int count = ROW_COUNT * COLUMN_COUNT; //创建操作队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //最大并发线程的数量 queue.maxConcurrentOperationCount = 5; NSBlockOperation *lastOperation = [NSBlockOperation blockOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:count -1]]; }]; for (int i = 0; i < count - 1; i ++) { NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:i]]; }]; [queue addOperation:operation]; //设置新开辟的线程 依赖于最后一个线程,所以最后一张在那个图片会先加载 [operation addDependency:lastOperation]; // //方法二 // [queue addOperationWithBlock:^{ // [self loadImage:[NSNumber numberWithInt:i]]; // }]; } }