A few days ago, I discussed with my colleagues the issue of forwarding Notification under multi-threading, so I would like to sort it out. Let's take a look at the official documentation first, which is written like this: In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself. Translated: In a multi-threaded application, Notification is forwarded in the thread in which it is posted, not necessarily in the thread in which the observer is registered. That is to say, the sending and receiving of Notification are all done in the same thread. To illustrate this, let's take a look at an example: Code Listing 1: Sending and processing Notification
The output is as follows:
As you can see, although we registered the notification observer in the main thread, the Notification posted in the global queue is not processed in the main thread. Therefore, we need to pay attention at this time. If we want to process UI-related operations in the callback, we need to ensure that the callback is executed in the main thread. At this point, there is a problem. If our Notification is posted in the secondary thread, how can we process this Notification in the main thread? Or to put it another way, if we want the post thread of a Notification to be different from the forwarding thread, what should we do? Let's see what the official document says: For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread. Here we talk about "redirection", which means that we capture these distributed notifications in the default thread where Notification is located, and then redirect them to the specified thread. One way to implement redirection is to customize a notification queue (note, not an NSNotificationQueue object, but an array) and let this queue maintain the Notifications we need to redirect. We still register a notification observer as usual. When a Notification comes, we first check whether the thread that posts this Notification is the thread we expect. If not, we store this Notification in our queue and send a signal to the expected thread to tell this thread that it needs to process a Notification. After receiving the signal, the specified thread removes the Notification from the queue and processes it. The official documentation has given sample code, which is borrowed here to test the actual results: Code Listing 2: Posting and forwarding a Notification in different threads
After running, the output is as follows:
As you can see, the Notification we threw in the global dispatch queue was received in the main thread as expected. For the specific analysis and limitations of this implementation, please refer to the official document Delivering Notifications To Particular Threads. Of course, a better way may be to subclass NSNotificationCenter ourselves, or write a separate class to handle this forwarding. Apple's strategy of posting and forwarding the same message in the same thread is probably based on thread safety considerations. The official documentation tells us that NSNotificationCenter is a thread-safe class, and we can use the same NSNotificationCenter object in a multi-threaded environment without locking. The original text is in the Threading Programming Guide, as follows:
We can add/remove notification observers in any thread, and we can post a notification in any thread. NSNotificationCenter has done a lot of work in terms of thread safety, does that mean we can sit back and relax? Let's go back to the last example and modify it a little bit, step by step: Code Listing 3: Common pattern for NSNotificationCenter
The above code is what we usually do: add a notification listener, define a callback, and remove the listener when the object to which it belongs is released; then post a notification somewhere in the program. Simple and clear, if all this happens in one thread, or at least the dealloc method is run in the thread of -postNotificationName: (Note: NSNotification post and forward are synchronous), then everything is OK, there is no thread safety problem. But what problems will arise if the dealloc method and -postNotificationName: method are not run in the same thread? Let's modify the above code again: Code Listing 4: Thread safety issues caused by NSNotificationCenter
This code adds a TEST_NOTIFICATION notification listener to the main thread and removes it from the main thread, while our NSNotification is posted in the background thread. In the notification processing function, we let the callback thread sleep for 1 second and then set the property i value. What will happen at this time? Let's take a look at the output first:
A classic memory error, the program crashed. In fact, from the output, we can see what happened. Let's briefly describe: When we register an observer, the notification center holds a weak reference to the observer to ensure that the observer is available. Of course, the above example is intentional, but it does not rule out the possibility of encountering similar problems in actual coding. Although NSNotificationCenter is thread-safe, it does not mean that we can guarantee thread safety when using it. If we are not careful, thread problems will still occur. So what should we do? Here are some good suggestions: Try to handle notification-related operations in one thread. In most cases, this will ensure that notifications work properly. However, we cannot be sure in which thread the dealloc method will be called, so this is still difficult. |
<<: It’s terrible: On average, a malicious program is created every 18 seconds on Android
>>: Apple's officially certified mobile phone cases are here, what do you think?
If the thinking section gives us the angle to thi...
Ginkgo trees are tall and straight, with fan-shap...
"The sun isn't that strong in autumn, so...
In October 2017, Keep surpassed Yuedongquan Runni...
Produced by Guangdong Science and Technology News...
Listen to some geological knowledge and understan...
1. Overview In iOS development, everyone is famil...
Younger, It is always the main theme of the brand...
Baidu's paid ranking is based on Baidu's ...
For many people, 1080P once represented high-qual...
Information flow advertising style - Post-feed pa...
WeChat Mini Program is an application that users ...
Compiled by Zhou Shuyi and Pingsheng New research...
Although the scale of Douyin 's vlogs is grad...
On June 1, 2021, the China Automobile Dealers Ass...