Explain NSRunLoop in detail

NSRunLoop seems to have become one of the three questions that must be asked in interviews alongside GCD and Runtime. But the strange thing is that we can find a lot of related code in GCD and Runtime, only NSRunLoop is rarely used in actual projects. As a result, we can only look at extremely abstract concepts, so here, I am not going to talk about the NSRunloop principle that has been covered in many articles, we will focus on how to use NSRunloop code in actual projects. Next, I'll assume that you already have some basic knowledge of RunLoop.

How to use NSRunLoop to optimize the problem of large image loading

How to observe the running status of the Runloop of the main thread

First of all, we need to be clear that each time a Runloop loop has a different state. So, what are the states? "



Probably the above state. There is also a corresponding method to observe the Runloop status in CoreFoundation. This thing is called CFRunLoopObserverRef, it is an observer, each Observer contains a callback (function pointer), when the state of RunLoop changes, the observer can receive the change through the callback.

So how to create a CFRunLoopObserverRef, the corresponding method is this. CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context);

Calling this method requires six parameters. The first parameter is used to allocate the memory of the observer object. The second parameter is used to set the events that the observer needs to pay attention to. For details, please refer to the comment in the callback function myRunLoopObserver. The third parameter is used to identify that the observer is executed when it enters the run loop for the first time. The fourth parameter is used to set the priority of the observer. The fifth parameter is used to set the callback function of the observer. The sixth parameter is used to set the operating environment of the observer.

The more important ones are the second and fifth parameters. The second parameter determines the type of Runloop state you observe, and the fifth parameter determines what actions you should do when your observer observes the Runloop running to a certain state.

So having said so much, how can we use optimized large image loading? If we now need to implement such an interface


There are a total of 15 pictures in this tableView, and the resolution of each picture is 2034 × 1525, that is to say, if we do not add any processing, we need to draw 15 large pictures on the screen in one Runloop cycle. Generally speaking, iOS devices with poor performance will definitely slide very poorly. So let's change the way of thinking. Since it is difficult to render 15 pictures at a time, can't we just divide the 15 pictures into 15 renderings? That is, the operation completed by the original runloop is completed in 15 runloops.

How to do this? It is to use the CFRunLoopObserverRef we described above. Imagine that there are 3 UIImageViews in the UITableViewCell in the picture above, the problem that causes the jam is nothing more than when cell.imageView.image = image. Because at this time the main thread will draw the picture to the imageView.

So, the optimized process becomes like this. 

So, in the first step, we first set an observer for the Runloop of the main thread. "



The activity type we registered is kCFRunLoopBeforeWaiting, and observe each time the runloop is about to go to sleep. Then Yes means that it will be observed every time the main thread runloop performs a loop. What is callback?




This place seems a bit difficult to understand. So let's not rush to see the callback method. Let's first look at how to deal with the datasource method of TableView.






1. Every time you enter the cellForIndex method, the task_5 method will be executed first. The content of this method is as follows.




In fact, it is to clear all the child controls in this Cell.
Then the task_1 method is executed.



Mainly responsible for adding the uilabel in the cell. Since the above two tasks are relatively less time-consuming tasks, our runloop is not used for special processing.

1. The next task_2, task_3, and task_4 all use our Runloop for special processing. What are these methods for?



The three of them have similar functions, which is to add an imageView to our cell and assign a value. This is also where it takes the most time. So, we dispatch them to multiple runloops to disperse execution.



"In our DWURunLoopWorkDistribution, there is an attribute called tasks, which is used to specifically store our tasks. Each task is a block. It stores the operations that the user wants us to perform. So, see here, what is executed in the callback method The operation should not be difficult to understand.


Determine whether the number of our tasks is 0. 0 indicates that there is no imageView that needs to be added.

When the number of tasks is greater than 0, take out a task, a task is a block, that is, a task that adds an imageView, and it can be executed at this time.

Since an activity of a runloop will only appear once, it means that the callback method will only be executed once in a runloop. Therefore, we ensure that only one imageView is added to a runloop. The effect of optimization is achieved.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326801798&siteId=291194637