[Turn] still using GCD? Let's take a look at nsoperation.

Source: Internet
Author: User

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 code
    Nsblockoperation * 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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.