If you don’t know some of the basics of RunLoop, I suggest you check out these two blog posts to help you understand the nature of thread survival

RunLoop(1)

Source code interpretation RunLoop, understand the future interview will add points

(Warm tip: here is a step by step exploration, the steps of the process is more, if you want to be wordy, you can directly take the code behind the package straight,2 sentences can be perfect use.)

During the interview, we often met many interviewers who asked us about RunLoop knowledge. Perhaps most of us know RunLoop, but we seldom use RunLoop in the project. In fact,RunLoop is used in many application scenarios, such as timer, thread survival, performance optimization and monitoring application lag . This blog is about thread survival.

AFNetworking is the framework that most network requests use. I believe you are familiar with it, and RunLoop is used to control the life cycle of child threads. It keeps the child thread in memory all the time. The advantage of this is that we don’t have to create – destroy – create – destroy the child thread all the time, which improves performance and has many benefits.

Let’s take a look at how you can control the life cycle of a thread (i.e., thread keepalive), allowing it to live as long as you want and destroying it whenever you want.

Once again, from simple to complex, we create a thread, using NSThread as an example (PThread,Operation,GCD, etc.).

To see when a thread is being destroyed, we can specify a MyThread, inherit an NSThread,

@interface MyThread : NSThread

And in the.m file, it basically monitors when the thread is destroyed.

-(void)dealloc{

NSLog(@”%s”,__func__);

}

So we can see exactly when MyThread is destroyed:

Clearly, the NSThread dies after the above code executes. So if we need to do something on a child thread frequently during development, we want that thread to remain undestroyed, so that we don’t have to create, destroy, create, destroy all the time.

So what do we do about it? Add a runloop directly to the child thread, because we know that when we get a runloop, the runloop will be created

It still didn’t work out. If you look closely at my previous two posts, you’ll notice one thing:

If Mode does not have any Source0 / Source1 / Timer/Observer, RunLoop immediately exit

So we can add any of these to the runloop to keep the thread from exiting, so let’s try:

Because it’s a child thread, we’re just going to use NSDefaultRunLoopMode, not another mode

If we think about it again, the run method just keeps the thread alive. What we really need to do is to perform other operations on the thread. So I write a complete thread survival example, as follows:

Above is a simple thread survival example, in fact, this has some disadvantages, let’s continue to explore.

Re-explore the problems existing in ‘thread survival’

So for simplicity, I’m going to create a new block, which is exactly the same as the previous block, so I’m going to create a jump of two controllers, because I want to see if the thread gets destroyed when the controller gets destroyed. Take a look at the following code:

When we look at the console, it’s clear that we’re not getting the results we want. Although the thread does exist and keeps doing things for me (the console can always print test), we find that the controller has been destroyed, but the thread on the controller has not been destroyed! We don’t see any output from the console. How did that happen? Is there a circular reference? Clearly not!

Self.Mythread is empty. You set self.mythread = nil; Write in the VC dealloc, you will find that the thread is still not destroyed!

The reason is that the thread never finishes executing, it is stuck in the code [[NSRunLoop currentRunLoop] run], so the NSLog(@”—- end —-“) never executes, the thread never terminates, so it will not be destroyed. So if you want a global thread that can be called from any page and never be destroyed, this thread will do just that. Now what we want is definitely that the thread will be destroyed when the current page exists and this VC is destroyed, and we want to control the life cycle of this thread, and it will be destroyed if it wants to be destroyed. So let’s see what we can do.

We know that the thread will be destroyed when it finishes executing, so we can destroy it by executing NSLog(@”—- end —-“), so the obvious idea is to stop the RunLoop of self.MyThread in the VC dealloc. Look at the code below.

The thread is still not destroyed.

Some people might think that this is probably a sign that the VC is going to be destroyed, and you are going to be destroyed in the VC stop method, is it too late? So, I use the button to execute the stop event. Please see below

At this point, the thread is still not destroyed (there is no dealloc in the log for the output thread).

[[NSRunLoop currentRunLoop] run

[[NSRunLoop currentRunLoop] run]; The cause of this, let’s first look at the official explanation for this method.

This method is the execution of an infinite loop runMode:beforeDate, which is efficient for handling an infinite loop. Roughly similar

white(1)

{runMode:beforeDate}

So we kind of know that this method is an infinite loop which means it can’t be turned off, so you can kind of view it as an infinite loop. The CFRunLoopStop(CFRunLoopGetCurrent()) we execute just stops runMode:beforeDate once in its infinite loop, it cannot stop all of them because it is constantly being created, so it is natural to use runMode:beforeD Ate this method to try to solve.

If you look at the console output, we’ve actually done using it if we want, and we’ve done destroying it if we don’t want, and we’ve done destroying the thread when the controller is destroying it (Stop is a BOOL,[NSDate distantFuture] is a big value).

If we want to destroy the thread, we will call the stop method in the VC dealloc.

Look at the above action, the controller should be destroyed, but the thread is still not destroyed

Why does a stop call cause the thread to be destroyed, but a stop call inside dealloc does not cause the thread to be destroyed?

WaitUntilDone = waitUntilDone = waitUntilDone = waitUntilDone

There are possible scenarios

So I’m going to change this parameter to YES.

The reason threads don’t destroy is this:

When we get to this point, the condition in while() will always be YES, which means that the code will always be repeated, so the runloop will still be running. So let’s change the condition: while(! Weakself. Stop&& weakSelf) change the condition to this (if here with **__strong** processing may generate circular reference).

Look at the running results, this operation is perfect solution!

Let’s see if clicking the stop mode has any effect! You’ll find it pops again! As follows:

The reason is simple: clicking stop has called stop,RunLoop has ended, it can’t do anything, it just hasn’t been destroyed. When you return, dealloc calls Stop again and lets it work again, which is bound to cause problems. So we just need to add a judgment:

This is really a perfect solution, regardless of how to operate, thread and controller will be destroyed! Let’s take a look at the results:

The result is perfect

Here we find that there are many steps before the results come out, and it feels a little troublesome, so we can directly encapsulate:

Thread encapsulation:

Encapsulation is very easy to use. Look at the execution call code first, and then the encapsulation

Initialize, call, do, and stop.

Perfect solution to the problem. Look at the following wrapper code:

Here, we basically said what to say, the package has been packaged, there is a need to take directly to call!

If the controller is destroyed, the thread will be destroyed as well, so there is no need to call stop in the dealloc. If the controller is destroyed, the thread will be destroyed as well.

2 sentences code complete save!

Extension — encapsulation of THE C language

Have the above package in fact already can, with the C language package as to understand:

As long as you change the content of the red circle, everything else is the same as before, and you can use it directly here.

Then I will continue to work hard to write other blogs, your support is my biggest motivation!

If you feel I have written to help you, please like to follow me, I will continue to update 😄

Thanks for supporting 🙏🙏🙏!