IOS knowledge comb – runloop

Runloop is actually a very common thing, basically every application framework has similar things, such as JS or Event Loop in Flutter, Android Looper.

Let’s take a look at the nature of runloop in its simplest case

roots

When I first learned programming, there was a classic problem of implementing four operations in C/C ++. In general, the following effect can be typed all the time:

The code might look something like this:

int main() { string str; double result; // Save the resultwhile(getline(cin,str))
    {
    // calculate
    cout << "Result is: "<< result << endl; }}Copy the code

Since we can always input new formulas, we naturally use a while loop to process the input, calculating the result when there is a new line of input and printing it out. Without new input, we actually block and wait.

This is actually the simplest runloop.

In real applications, it’s just a little bit more input, a little bit more complex tasks, and the basic framework is still a while loop.

See a pseudocode on the Internet pretty clear:

function loop() {
  initialize();
  do {
      var message = get_next_message();
      process_message(message);
  } while(message ! = quit); }Copy the code

Understand Runloop in depth

There’s a lot of detail about the actual implementation of Runloop, and the Core Foundation framework is open source, so you can dig deep here.

IOS multithreading: “RunLoop” exhaustive summary, this article speaks well, recommended reading. Many of the details are not covered in this article.

Mode

Runloop has a mode concept at runtime, and runloop only processes events of the current mode.

For example, if we have mode1 and mode2, mode1 corresponds to 3 events, mode2 corresponds to 2 events, and if the current runloop is in mode1, only 3 events corresponding to mode1 will be processed.

Specifically, runloop exposes two modes: kCFRunLoopDefaultMode and UITrackingRunLoopMode. Normally, the main thread is in DefaultMode, but when sliding scrollView, The main thread is in TrackingMode. By default, our NSTimer event is bound to DefaultMode, which will result in no NSTimer event being fired when the ScrollView is swiped.

To solve this problem, Runloop gives the concept of CommonMode. CommonMode is not a specific Mode, but can be understood as a set of modes. In this case, DefaultMode and TrackingMode are in fact. Add Timer to CommonMode and the Timer is executed in both DefaultMode and TrackingMode.

The Mode thing, in practice, is almost never used, except to make the use of the Timer difficult.

So why did Apple design Mode in Runloop?

There are no valuable discussions to be found online, but a quick guess might be that, in some scenarios, you can only handle the events that are required for that scenario. This may be based on the assumption that in a particular scenario, the CPU is overwhelmed and needs to stop all other tasks and focus on the tasks in the current scenario. For example, if task A requires 90 percent of the CPU and other miscellaneous events require 40 percent of the CPU, it might make sense to stop those miscellaneous tasks and focus on the current scene.

If the CPU is not running full, then the split of Mode is meaningless, at best a very bad priority adjustment (low priority is stuck).

Consider other platforms’ implementations of EventLoop, which usually provide simple priority setting capabilities.

In general, I think the Mode design is quite weak.

Runloop for the child thread

By default, Runloop is not enabled by child threads. When you think about it, it makes perfect sense. When Runloop is enabled, threads will block even when there are no events, which is called saving when needed and wasting resources when not needed. Therefore, child threads definitely cannot open Runloop by default. Without open the Runloop cases, involves the Runloop asynchronous calls are unusable, mainly is the NSTimer, performSelector: afterDelay:, network request callback, etc.

The solution is to start the runloop of the current thread with [[NSRunLoop currentRunLoop] run].

Runloop-related features

  1. Autoreleasepool: Enters the pool at the beginning of each runloop and leaves the pool at the end. To release the AutoRelease object when autoReleasepool is not explicitly declared.
  2. Interface update: UI operations mark the corresponding UIView/CALayer as pending, and actual drawing is performed at the end of each iteration.