This article is very well written, basic usage is involved, I have the article mentioned in the example is written in the demo,Original Address:iOS Multithreading-Learn how to "nsoperation" multiple threads thoroughly
Demo Download: Https://github.com/wangdachui/multithreading.git
1. Nsoperation Introduction
Nsoperation is a multi-threaded solution that Apple offers to us. In fact, Nsoperation is based on a higher level of GCD encapsulation, but it is easier to use than GCD, and the code is more readable.
Nsoperation need to cooperate with Nsoperationqueue to realize multithreading. because, by default, Nsoperation performs operations synchronously when used alone, and does not have the ability to open new threads, asynchronous execution is only possible with Nsoperationqueue.
Because Nsoperation is based on GCD, it is similar to GCD, where nsoperation is equivalent to a task in gcd, while Nsoperationqueue is equivalent to a queue in GCD. Nsoperation the use of multithreading is divided into three steps:
- Create a task: first encapsulate the action that needs to be performed into a Nsoperation object.
- Create queue: Create a Nsoperationqueue object.
- Join the task to the queue: then add the Nsoperation object to the Nsoperationqueue.
After that, the system automatically takes the nsoperation out of the nsoperationqueue and executes the operation in the new thread.
Below we will learn the basic use of nsoperation and Nsoperationqueue.
Basic use of 2.NSOperation and Nsoperationqueue 1. Create a task
Nsoperation is an abstract class and cannot encapsulate tasks. We only use its subclasses to encapsulate the task. We have three ways to encapsulate tasks.
- Use Subclass Nsinvocationoperation
- Use Subclass Nsblockoperation
- Defines subclasses that inherit from Nsoperation, encapsulating the task by implementing an internal appropriate method.
To perform the operation synchronously without using nsoperationqueue and using nsoperation alone, let's learn three ways to create the following tasks.
1. Using subclasses
- NSInvocationOperation:
// 1.创建NSInvocationOperation对象NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];// 2.调用start方法开始执行操作[op start];- (void)run{ NSLog(@"------%@", [NSThread currentThread]);}
Output Result:
2016-09-05 14:29:58.483 nsoperation[15834:2384555]------<nsthread:0x7fa3e2e05410>{number = 1, name = main}
As you can see, Nsinvocationoperation performs an operation on the main thread without using Nsoperationqueue and using nsinvocationoperation alone, and no new threads are opened.
Let's look at nsblockoperation below.
2. Using subclasses
- NSBlockOperation
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ // 在主线程 NSLog(@"------%@", [NSThread currentThread]);}];[op start];
Output Result:
2016-09-05 14:33:15.268 nsoperation[15884:2387780]------<nsthread:0x7fb2196012c0>{number = 1, name = main}
As we can see, Nsblockoperation is also performing operations on the main thread without using Nsoperationqueue and using nsblockoperation alone, and does not open a new thread.
However, Nsblockoperation also provides a method addExecutionBlock: by which additional addExecutionBlock: operations can be added for nsblockoperation, which are executed concurrently on other threads.
- (void)blockOperation{ NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ // 在主线程 NSLog(@"1------%@", [NSThread currentThread]); }]; // 添加额外的任务(在子线程执行) [op addExecutionBlock:^{ NSLog(@"2------%@", [NSThread currentThread]); }]; [op addExecutionBlock:^{ NSLog(@"3------%@", [NSThread currentThread]); }]; [op addExecutionBlock:^{ NSLog(@"4------%@", [NSThread currentThread]); }]; [op start];}
Output Result:
2016-09-05 14:36:59.353 nsoperation[15896:2390616] 1------<nsthread:0x7ff633f03be0>{number = 1, name = main}
2016-09-05 14:36:59.354 nsoperation[15896:2390825] 2------<nsthread:0x7ff633e24600>{number = 2, name = (NULL)}
2016-09-05 14:36:59.354 nsoperation[15896:2390657] 3------<nsthread:0x7ff633c411e0>{number = 3, name = (NULL)}
2016-09-05 14:36:59.354 nsoperation[15896:2390656] 4------<nsthread:0x7ff633f1d3e0>{number = 4, name = (NULL)}
As you can see, the blockOperationWithBlock: actions in the method are performed in the main thread, and the addExecutionBlock: operations in the methods are performed in other threads.
3. Define subclasses that inherit from Nsoperation
First define a subclass that inherits from Nsoperation, overriding the Main method
YSCOperation.h
#import <Foundation/Foundation.h>@interface YSCOperation : NSOperation@end
Yscoperation.m
#import "YSCOperation.h"@implementation YSCOperation/** * 需要执行的任务 */- (void)main{ for (int i = 0; i < 2; ++i) { NSLog(@"1-----%@",[NSThread currentThread]); } }@end
Then use the time to import the header file YSCOperation.h .
// 创建YSCOperationYSCOperation *op1 = [[YSCOperation alloc] init];[op1 start];
Output Result:
2016-09-05 18:15:59.674 nsoperation[16566:2501606] 1-----<nsthread:0x7f8030d05150>{number = 1, name = main}
2016-09-05 18:15:59.675 nsoperation[16566:2501606] 1-----<nsthread:0x7f8030d05150>{number = 1, name = main}
As you can see, in the case of not using Nsoperationqueue and using custom subclasses alone, the operation is performed on the main thread and no new threads are opened.
Below we briefly talk about the creation of Nsoperationqueue.
2. Create a queue
Slightly different from the concurrent queues and serial queues in GCD: NSOperationQueue There are altogether two types of queues: The primary queue, the other queue. The other queues include both serial and concurrency features. Below is the basic creation method and characteristics of the home row and other queues.
- Primary queue
- Other queues (non-host columns)
3. Adding tasks to the queue
The front said, Nsoperation need to cooperate with nsoperationqueue to achieve multithreading.
Then we need to add the created task to the queue. There are a total of two methods
- (void)addOperation:(NSOperation *)op;
- You need to create a task before adding the created task to the created queue
-(void) addoperationtoqueue{//1. Create queue Nsoperationqueue *queue = [[NS] Operationqueue alloc] init]; 2. Create action//create nsinvocationoperation nsinvocationoperation *OP1 = [[Nsinvocationoperation alloc] Initwithtarget:sel F selector: @selector (run) Object:nil]; Create nsblockoperation nsblockoperation *op2 = [nsblockoperation blockoperationwithblock:^{for (int i = 0; i < 2; ++i) {NSLog (@ "1-----%@", [Nsthread CurrentThread]); } }]; 3. Add action to queue: addoperation: [Queue ADDOPERATION:OP1]; [OP1 start] [queue addoperation:op2]; [Op2 start]}-(void) run{for (int i = 0; i < 2; ++i) {NSLog (@ "2-----%@", [Nsthread CurrentThread]); }}
Output Result:
2016-09-05 17:06:00.241 nsoperationqueue[16201:2452281] 1-----<nsthread:0x7fe4824080e0>{number = 3, name = (null )}
2016-09-05 17:06:00.241 nsoperationqueue[16201:2452175] 2-----<nsthread:0x7fe482404a50>{number = 2, name = (null )}
2016-09-05 17:06:00.242 nsoperationqueue[16201:2452175] 2-----<nsthread:0x7fe482404a50>{number = 2, name = (null )}
2016-09-05 17:06:00.241 nsoperationqueue[16201:2452281] 1-----<nsthread:0x7fe4824080e0>{number = 3, name = (null )}
It can be seen that nsinvocationoperation and Nsoperationqueue can open new threads, perform concurrent execution nsblockoperation and Nsoperationqueue can also open new threads for concurrent execution.
- (void)addOperationWithBlock:(void (^)(void))block;
- Instead of creating a task, add a task to the block and join the task block directly into the queue.
- (void)addOperationWithBlockToQueue{ // 1. 创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2. 添加操作到队列中:addOperationWithBlock: [queue addOperationWithBlock:^{ for (int i = 0; i < 2; ++i) { NSLog(@"-----%@", [NSThread currentThread]); } }];}
Output Result:
2016-09-05 17:10:47.023 nsoperationqueue[16293:2457487]-----<nsthread:0x7ffa6bc0e1e0>{number = 2, name = (NULL) }
2016-09-05 17:10:47.024 nsoperationqueue[16293:2457487]-----<nsthread:0x7ffa6bc0e1e0>{number = 2, name = (NULL) }
You can see that addoperationwithblock: and Nsoperationqueue can open a new thread for concurrent execution.
3. Key to control serial execution and parallel execution
As we said before, the other queues created by Nsoperationqueue have serial, concurrency, and we demonstrate concurrency, so how does his serial function work?
Here is a key parameter maxConcurrentOperationCount called the maximum concurrency number .
- maximum concurrency:
maxconcurrentoperationcount
-
maxconcurrentoperationcount by default-1 , which means that no restrictions are imposed, and concurrency is performed by default.
- when
maxconcurrentoperationcount is 1 o'clock, serial execution occurs.
- when
maxconcurrentoperationcount is greater than 1 o'clock for concurrent execution, this value should not exceed the system limit, even if you set a large value, the system will automatically adjust.
-(void) opetationqueue{//create queue Nsoperationqueue *queue = [[Nsoperationqueue alloc] init]; Set maximum number of concurrent operations//Queue.maxconcurrentoperationcount = 2; Queue.maxconcurrentoperationcount = 1; It becomes a serial queue//add operation [Queue addoperationwithblock:^{NSLog (@ "1-----%@", [Nsthread CurrentThread]); [Nsthread sleepfortimeinterval:0.01]; }]; [Queue addoperationwithblock:^{NSLog (@ "2-----%@", [Nsthread CurrentThread]); [Nsthread sleepfortimeinterval:0.01]; }]; [Queue addoperationwithblock:^{NSLog (@ "3-----%@", [Nsthread CurrentThread]); [Nsthread sleepfortimeinterval:0.01]; }]; [Queue addoperationwithblock:^{NSLog (@ "4-----%@", [Nsthread CurrentThread]); [Nsthread sleepfortimeinterval:0.01]; }]; [Queue addoperationwithblock:^{NSLog (@ "5-----%@", [Nsthread CurrentThread]); [Nsthread sleepfortimeinterval:0.01]; }]; [Queue addoperationwithblock:^{NSLog (@ "6-----%@", [Nsthread curRentthread]); [Nsthread sleepfortimeinterval:0.01]; }];}
Maximum concurrency of 1 output:
2016-09-05 17:21:54.124 nsoperationqueue[16320:2464630] 1-----<nsthread:0x7fc892d0b3a0>{ Number = 2, name = (null)}
2016-09-05 17:21:54.136 nsoperationqueue[16320:2464631] 2-----<nsthread: 0x7fc892c0a7b0>{number = 3, name = (null)}
2016-09-05 17:21:54.148 nsoperationqueue[16320:2464630] 3-----< Nsthread:0x7fc892d0b3a0>{number = 2, name = (null)}
2016-09-05 17:21:54.160 nsoperationqueue[16320:2464631] 4--- --<nsthread:0x7fc892c0a7b0>{number = 3, name = (null)}
2016-09-05 17:21:54.171 nsoperationqueue[ 16320:2464631] 5-----<nsthread:0x7fc892c0a7b0>{number = 3, name = (null)}
2016-09-05 17:21:54.184 NSOPERATIONQUEUE[16320:2464630] 6-----<nsthread:0x7fc892d0b3a0>{number = 2, name = (null)}
The maximum number of concurrent output results is 2:
2016-09-05 17:23:36.030 nsoperationqueue[16331:2466366] 2-----<nsthread:0x7fd729f0f270>{number = 3, name = (null )}
2016-09-05 17:23:36.030 nsoperationqueue[16331:2466491] 1-----<nsthread:0x7fd729f4e290>{number = 2, name = (null )}
2016-09-05 17:23:36.041 nsoperationqueue[16331:2466367] 3-----<nsthread:0x7fd729d214e0>{number = 4, name = (null )}
2016-09-05 17:23:36.041 nsoperationqueue[16331:2466366] 4-----<nsthread:0x7fd729f0f270>{number = 3, name = (null )}
2016-09-05 17:23:36.053 nsoperationqueue[16331:2466366] 6-----<nsthread:0x7fd729f0f270>{number = 3, name = (null )}
2016-09-05 17:23:36.053 nsoperationqueue[16331:2466511] 5-----<nsthread:0x7fd729e056c0>{number = 5, name = (null )}
As you can see: When the maximum concurrency is 1 o'clock, the task is serially executed sequentially. When the maximum concurrent number is 2 o'clock, the task is executed concurrently. And the number of open threads is determined by the system and does not need to be managed by us. So, is it a lot simpler than GCD?
4. Operational dependencies
The most appealing thing about nsoperation and Nsoperationqueue is that it can add dependencies between operations. For example, there is a, B two operations, where a performs operations, B to perform operations, then you need to let B rely on a. Specific as follows:
- (void)addDependency{ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1-----%@", [NSThread currentThread]); }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2-----%@", [NSThread currentThread]); }]; [op2 addDependency:op1]; // 让op2 依赖于 op1,则先执行op1,在执行op2 [queue addOperation:op1]; [queue addOperation:op2];}
Output Result:
2016-09-05 17:51:28.811 operation Dependent [16423:2484866] 1-----<nsthread:0x7fc138e1e7c0>{number = 2, name = (NULL)}
2016-09-05 17:51:28.812 operation Dependent [16423:2484866] 2-----<nsthread:0x7fc138e1e7c0>{number = 2, name = (NULL)}
You can see that no matter how many times it runs, the result is OP1 executed first, op2 after execution.
5. Some other methods
iOS multithreaded Programming--nsoperation (RPM)