Multithreading nsthiread GCD nsoperation runloop for IOS development

Time:2021-5-5

Process and thread in IOS

Generally speaking, an app is a process
In IOS development, XPC is seldom used, and threads are mostly used.
In IOS development, in order to ensure fluency and thread safety, all UI related operations should be placed in the main thread, so sometimes the main thread is also called UI thread.
Affect the UI experience, time-consuming operation, try to put in the non main thread. Such as network request and local IO operation.
In IOS development, the knowledge points about multithreading mainly include: nsthread, GCD, nsoperation and runloop

NSThread

Nsthread is a thread. Its bottom layer is the encapsulation of ptthread, which is used to create a new thread. We can also obtain information through some properties in nsthread, such as currentthread and ismainthread.


@property (readonly) BOOL isMainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (class, readonly, strong) NSThread *currentThread;

For example, we request the image from the network in the sub thread (because the network request is time-consuming) and display it in the UI page.

NSThread *downLoadImageThread = [[NSThread alloc] initWithBlock:^{
    //Put the time-consuming code to get the image into the sub thread for execution
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:item.picUrl]]];
    self.rightimageView.image = image;  // UI operation must be executed in the main thread, otherwise it will alarm
}];
//Set thread name
downLoadImageThread.name = @"downLoadImageThread";
[downLoadImageThread start]; // Execute this thread

In the above code, we put the operation of UI display in the sub thread, which is not standard, because in IOS, the code of UI operation must be put in the main thread, otherwise the system will alarm.

The alarm is as follows:

GCD

GCD is the code that starts with dispatch. GCD solves the inconvenience of nsthread. It turns the operation on thread into the operation on queue. It simplifies our management of threads. GCD implements a thread pool at the bottom to automatically manage threads. We only need to operate on the queue. Like thread, queue is divided into main queue and non main queue. Main queue stores main thread, while non main queue stores non main thread.
As shown in the figure below:

There are three main queues in GCD
The first is the main queue corresponding to the main thread.

dispatch_ queue_ main_ t mainQueue = dispatch_ get_ main_ queue(); // Get home queue

Second: non main threads are divided into four non main queues with different priorities according to their priority. High/default/Low/Background
The function is defined as follows: the first parameter is the priority selection, and the second parameter can be filled with 0 if it is not used temporarily

dispatch_ queue_ global_ t downoadQueue = dispatch_ get_ global_ queue(DISPATCH_ QUEUE_ PRIORITY_ DEFAULT, 0); // Get non home queue

Third: Custom queue
The creation function is as follows: the first parameter is to set the name of the queue, and the second parameter is to set whether the queue is serial or concurrent. As for the concepts of serial queue and concurrent queue, we will analyze them carefully.
Serial: Dispatch_ QUEUE_ SERIAL
Parallel: Dispatch_ QUEUE_ CONCURRENT


dispatch_queue_t dispatch_queue_create(const char *_Nullable label,
		dispatch_queue_attr_t _Nullable attr);

The use of GCD is divided into synchronous execution and asynchronous execution.
Synchronous execution is the execution of the code line by line. The function calls are as follows:


dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);

The first parameter is the queue name, and the second parameter is the code block,In the code block is the code we want to execute in the thread
Asynchronous execution means that the code can jump out of the current code block and execute the code after the current code. Its function calls are as follows:


dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

The first parameter is the queue name, and the second parameter is the code block to execute.
Another way of execution is to delay execution. The function calls are as follows:


void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
		dispatch_block_t block);

The first parameter is delay time, and the latter parameter is the same as above.
Concept interpretation
Synchronous execution: can only execute tasks in the current thread, not have the ability to open a new thread.
Asynchronous execution: asynchronously adds a task to the specified queue. It does not wait and can continue to execute the task. It can execute tasks in new threads and has the ability to open (create) new threads.
Serial queue: only one task is executed at a time. Let the tasks be executed one by one. Only one thread is started. After one task is executed, the next task is executed.
Parallel queue: multiple tasks can be executed simultaneously( Multiple threads can be started and tasks can be executed at the same time.)
be careful:The concurrency function of parallel queue is only effective under asynchronous method.

Here, I will give an example to explain the difference between serial queue and concurrent queue, as well as the difference between synchronous execution and asynchronous execution.
Suppose that there are five people going through an access control. There are 10 entrances in this access control. The administrator can decide how many entrances to open at the same time, and whether to let one person pass alone or multiple people pass together at the same time. However, by default, the administrator only opens one entrance, and a channel can only pass through one person at a time.
In this story, people are like tasks, administrators are like systems, and entries represent threads.
Five people said there were five tasks, and 10 entries represented 10 threads.
A serial line is like a long line of five people.
Concurrent queues are like five people in multiple teams, such as two or three.
The synchronization task is like an administrator opening only one entry (the current thread).
Asynchronous tasks are like administrators opening multiple entries (current thread + new thread) at the same time.
“Asynchronous execution + concurrent queue” can be understood as: now the administrator has opened multiple entrances (such as three entrances), and five people form multiple teams (such as three teams), so that these five people can pass through the access control at the same time.
“Synchronous execution + concurrent queue” can be understood as: now the administrator only opens one entry, and five people form multiple teams. Although these five people have formed many teams, only one entrance has been opened. Although these five people want to pass quickly, one entrance can only pass one person at a time, so we have to walk one by one. The result of the performance is: pass through the entrance in turn.
To change to the language in GCD means:
“Asynchronous execution + concurrent queue” means that the system has opened multiple threads (main thread + other sub threads), and multiple tasks can run at the same time.
“Synchronous execution + concurrent queue” means that the system only turns on one main thread by default, and does not turn on any child threads. Although the tasks are in the concurrent queue, they can only be executed one by one.
Next, I use GCD to optimize the warning problem of the above UI operation in the sub thread:

//Method 3: using GCD
    dispatch_ queue_ global_ t downoadQueue = dispatch_ get_ global_ queue(DISPATCH_ QUEUE_ PRIORITY_ DEFAULT, 0); // Get non home queue
    dispatch_ queue_ main_ t mainQueue = dispatch_ get_ main_ queue(); // Get home queue
    //In the non main queue, it is executed asynchronously to perform the time-consuming operation of getting pictures
    //Asynchronous: open multiple doors, can pass through the door at the same time (multithreading), with the ability to open new threads
    dispatch_ Async (downoadqueue, ^ {// asynchronous, non main queue)
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:item.picUrl]]];
        dispatch_ Async (mainqueue, ^ {// asynchronous, executing UI operations in the main thread
            //Execute UI operation in main thread, execute asynchronously
            self.rightimageView.image = image;  // UI operation must be executed in the main thread, otherwise it will alarm
        });
    });

NSOperation

Because GCD has no object-oriented encapsulation, and the code we need to execute is written in the block, if we want to cancel the execution of general block, or to realize synchronization and mutual exclusion among multiple blocks, the operation is more complex.
For the higher level encapsulation, the system provides us with nsoperation, which is an object-oriented encapsulation of GCD.
About nsoperation, I’ll share it later after I have a deep understanding.

Runloop

With the thread is how to operate the business logic, as well as the execution of the business logic, for each thread, the system provides an internal implementation, the internal implementation is runloop. Runloop is to cooperate with the underlying thread to handle our gestures, interactions, and port management.

For example, why does the main thread exist all the time and not be destroyed? The bottom layer is the runloop, which makes the main thread sleep when it is not executing.

Finally, we have a macro understanding of IOS multithreading.

The above is the details of the multithreaded nsthiread GCD nsoperation runloop of IOS development. For more information about multithreading of IOS development, please pay attention to other related articles of developer!