Transferred from: HTTP://WWW.JIANSHU.COM/P/0C241A4918BF
In iOS development, when it comes to multithreading, it must be gcd the first time you think about it. GCD is a powerful multi-threaded solution, able to solve the vast majority of multi-threaded problems, but he is easy to learn and difficult to master and everywhere is the characteristics of the pit is destined to use it has a certain degree of difficulty. And a lot of people hang on the mouth every day gcd, in fact, its practical application is not very understanding.
Moreover, in the current mainstream development model, the vast majority of the use of multithreading is the network data requests and network image loading, these two points on the Afnetwork+sdwebimage has been able to meet almost all the needs. And a small part of the rest, simple and easy to use nsoperation is undoubtedly more advantageous than the GCD.
Therefore, if you insist on "gcd dafa good", then you do not have to see it here. If you want to try an easier way, then let me do it.
What is Nsoperation?
Like GCD, Nsoperation is also a multi-threaded solution that Apple offers to us. In fact, it is also based on GCD, but has greater controllability and code readability than GCD.
Nsoperation is an abstract base class with little practical value. What we use most is the system encapsulated well NSInvocationOperation
and NSBlockOperation
.
But nsoperation some common methods, you need to know.
NSOperation * operation = [[NSOperation alloc]init];//开始执行[operation start];//取消执行[operation cancel];//执行结束后调用的Block[operation setCompletionBlock:^{ NSLog(@"执行结束");}];
Using Nsinvocationoperation
Nsinvocationoperation is used in a similar way to adding events to a button, requiring an object and a selector. The method of use is very simple.
Let's write a method first.
- (void)testNSOperation{NSLog(@"我在第%@个线程",[NSThread currentThread]);}
And then call it
//创建NSInvocationOperation * invo = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testNSInvocationOperation) object:nil];//执行[invo start];
Get the results of this execution
Execution results
We can see that nsinvocationoperation is in fact synchronous execution, so it is used alone, this thing also has no egg, it needs to cooperate with the nsoperationqueue we introduced later to implement multi-threaded call, So here we just have to remember that there is such a thing on the line.
Using Nsblockoperation
- Finally, our first priority today.
Nsblockoperation is also a subclass of Nsoperation that supports concurrent implementation of one or more blocks, which is simple and convenient to use.
Execute the following codeNsblockoperation * Blockoperation = [[Nsblockoperation blockoperationwithblock:^{NSLog (@ "1 in%@ thread", [nsthread CurrentThread]);}]; [Blockoperation addexecutionblock:^{nslog (@ "2 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]);}]; [Blockoperation addexecutionblock:^{nslog (@ "3 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]);}]; [Blockoperation addexecutionblock:^{nslog (@ "4 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]);}]; [Blockoperation addexecutionblock:^{nslog (@ "5 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]);}]; [Blockoperation addexecutionblock:^{nslog (@ "6 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]);}];
Here we do two more times and compare results
Results of the first execution
Results of the second execution
Results of the third implementation
- By comparing three different results, we can see that nsblockoperation does realize multithreading. But we can see that it's not about putting all the blocks in the sub-threads. Through the above print record we can find that it will first put the block in the main thread execution, if the main thread has to be executed code, the new thread, but the maximum number of concurrent 4 (including the main thread). If the number of blocks is greater than 4, then the remaining blocks will wait for a thread to be idle and then be assigned to the thread, and still be assigned priority to the main thread.
- In addition, the code in the same block is executed synchronously.
To prove the above conjecture, we add more blocks to the block, adding two lines of code to each block.
Nsblockoperation * Blockoperation = [Nsblockoperation blockoperationwithblock:^{NSLog (@ "1 in%@ thread", [Nsthread CurrentThread]);NSLog (@ "1haha");}]; [Blockoperation addexecutionblock:^{NSLog (@ "2 in%@ thread", [Nsthread CurrentThread]);NSLog (@ "2haha");}]; [Blockoperation addexecutionblock:^{NSLog (@ "3 in%@ thread", [Nsthread CurrentThread]);NSLog (@ "3haha");}]; [Blockoperation addexecutionblock:^{NSLog (@ "4 in%@ thread", [Nsthread CurrentThread]);NSLog (@ "4haha");}]; [Blockoperation addexecutionblock:^{NSLog (@ "5 in%@ thread", [Nsthread CurrentThread]);NSLog (@ "5haha");}]; [Blockoperation addexecutionblock:^{NSLog (@ "6 in%@ thread", [Nsthread CurrentThread]);NSLog (@ "6haha");}]; [Blockoperation addexecutionblock:^{NSLog (@ "7 in%@ thread", [nsthread CurrentThread]); nslog (@ "7haha");}]; [Blockoperation addexecutionblock:^{nslog (@ "8 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]); nslog (@ "8haha");}]; [Blockoperation addexecutionblock:^{nslog (@ "9 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]); nslog (@ "9haha");}]; [Blockoperation addexecutionblock:^{nslog (@ "10 in section%@ threads", [ Span class= "hljs-built_in" >nsthread CurrentThread]); nslog (@ "10haha");}]; [Blockoperation start];
And then we'll look at the execution results.
Execution results
]
- As we can see, the maximum concurrency is 4, and the block using the same thread must wait for the code of the previous block to complete before it executes and executes synchronously.
About maximum concurrent numbers
In the results we have just seen that the maximum concurrency is 4, but this value is not a fixed value. 4 is the result of my running on the simulator, and if I run with the real machine, the maximum concurrency is always 2. Therefore, the specific maximum concurrency number and the operating environment are also related. We don't have to dwell on this number.
So nsblockoperation is not an ideal multithreaded solution, although we can create UI in the first block, do data processing in other blocks, but still feel uncomfortable.
Don't worry, we'll keep looking down.
Custom Nsoperation
Yes, you are right, nsoperation can be customized. If NSInvocationOperation
and NSBlockOperation
can't meet your needs, you can choose to customize a nsoperation.
Through the above analysis, we found that the system provides two kinds of nsoperation is certainly not enough to meet our needs.
So do we need to customize a nsoperation?
The answer is, no need.
Custom Nsoperation is not difficult, but still have to write a lot of code, this is against our simple implementation of multi-threaded intention. Besides, next I will introduce our true protagonist--nsoperationqueue today. So, I'm going to skip this one step directly.
If you do have a classmate, you can have a private messages to me ... If a lot of people need it. I will write an extra article ...
(Reader: You TM don't talk so much nonsense (╯‵-′) ╯︵┻━┻)
Nsoperationqueue Simple to use
Finally, it's our turn to be the protagonist today.
As the name implies, Nsoperationqueue is the queue that executes nsoperation, we can put one or more Nsoperation objects in the queue to execute.
Like the nsinvocationoperation we've covered above, we'll put it in the queue.
//依然调用上面的那个方法NSInvocationOperation * invo = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testNSInvocationOperation) object:nil];NSOperationQueue * queue = [[NSOperationQueue alloc]init];[queue addOperation:invo];
Take a look at the results
Execution results
Now it's been put in a sub-thread to execute the
Let's add the nsblockoperation we just wrote to this queue.
start];[queue addOperation:blockOperation];
And then we'll see what happens.
Execution results
As we can see, nsinvocationoperation and nsblockoperation are executed asynchronously, and each block in the nsblockoperation is executed asynchronously and is executed in the child thread, and the inside of each block is still executed synchronously.
Is it easy to use and powerful?
The Nsoperation object that is placed in the queue does not need to call the start
method, Nsoperationqueue will automatically invoke it at "the right Time"
A simpler way to use
In addition to the previous usage of adding nsoperation to the queue, Nsoperationqueue provides a simpler way to implement multi-threaded calls with the following two lines of code
NSOperationQueue * queue = [[NSOperationQueue alloc]init];[queue addOperationWithBlock:^{ //这里是你想做的操作}];
You can add one or more blocks at the same time to implement your operation
What, is it not easy to die?
(This article only needs to look at these two sentences, right????????????????????? )
adding dependencies
If Nsoperationqueue can only do this, then I don't have to go through a lot of trouble.
The most appealing thing about Nsoperationqueue is its ability to add dependencies.
For example, if a relies on B, then a will never execute until the execution of B is completed.
The sample code is as follows
{Nsinvocationoperation * OP1 = [[Nsinvocationoperation Alloc]initwithtarget:Self selector:@selector (testNSInvocationOperation1) Object:NIL];Nsinvocationoperation * OP2 = [[nsinvocationoperation alloc]initwithtarget:self selector: @selector (Testnsinvocationoperation2) Object:nil]; nsoperationqueue * queue = [[nsoperationqueue alloc]init];[ OP2 ADDDEPENDENCY:OP1]; [Queue ADDOPERATION:OP1]; [Queue addoperation:op2];} -(void) testnsinvocationoperation1{ nslog (@ "I am op1 I'm in%@ thread", [ Nsthread CurrentThread]);} -(void) testnsinvocationoperation2{ nslog (@ "I am op2 I'm in%@ thread", [ Nsthread CurrentThread]);
And then no matter how many times you run, the result must be this
Inevitable result
This is the benefit of dependency, OP2 must be executed after OP1, which will greatly facilitate our process control.
There are three points to note when using dependencies
1. Do not set up circular dependencies, which can cause deadlocks, cause the same circular reference
2. Using dependency recommendations only with nsinvocationoperation,nsinvocationoperation and nsblockoperation will result in dependencies not being implemented properly.
3. Dependencies not only take effect in the same queue, but the dependencies that are set before the Nsoperation objects in different queues take effect
March 29, 2016 11:16:00 update
There's a small problem with the code that was put in place. Adding dependent code is best placed before adding a queue
As I said earlier, Nsoperationqueue will automatically perform the task at "the right time", so you can't be sure when it's going to happen, it's possible that the task you added a second ago will be executed when you're ready to add dependencies, and there will be an illusion of dependency invalidation. The code has been corrected, thank you for your comment area reminders
Setting the priority level
Each Nsoperation object is a queuePriority
property that represents the queue priority. It is an enumeration value that has so many levels to choose from
Priority level selectable
You can set it up and try it, but it doesn't always work, and I haven't found the reason yet. Therefore, it is recommended to use dependencies to control the process.
If a small partner knows how to make the priority always effective, please let me know ...
Other operations and precautions
The nsoperationqueue provides both pause and cancel operations.
Setting a pause only needs to set the queue's suspended
properties to YES
either NO
Cancel you can choose to call a nsoperation cancle
method, or you can call the queue cancelAllOperations
method to cancel all threads
It should be emphasized here that the so-called pauses and cancellations do not immediately pause or cancel the current operation, but do not invoke the new nsoperation.
Changing the maxconcurrentoperationcount of a queue can set the maximum number of concurrent numbers.
There are still two points to note here.
1. The maximum concurrency is capped, even if you set it to 100, it will not exceed its upper limit, and the number of this limit is determined by the specific operating environment
2. Set the maximum concurrency number must be set immediately after Nsoperationqueue initialization, as said above, the Nsoperation object that is placed in the queue is determined by the queue itself when it is executed, it is possible that your side of the add is immediately executed. So if you want the settings to take effect, be sure to set them immediately after initialization.
Conclusion
Here, nsoperation knowledge we have already introduced, if you try to use one or two times, you will fall in love with him.
Author level limited, incorrect place please point out
[Turn] still using GCD? Let's take a look at nsoperation.