SoFunction
Updated on 2025-04-03

iOS realizes the effect of multiple pop-up boxes popping up in sequence in sequence

Sometimes there is a need to do this: after the app is finished running, it loads RootVC, and some operations are needed at this time, such as checking for updates, etc. At this time, two or even more pop-up boxes may need to pop up in sequence.

This article will use the system's UIAlertController as an example. Of course, if it is customized, you should also look at this article and how to deal with multiple pop-ups.

First, if it is written as follows:

- (void)viewDidAppear:(BOOL)animated {
 [super viewDidAppear:animated];
 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Box 1" message:@"First pop-up box" preferredStyle:UIAlertControllerStyleAlert];
 [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 [self presentViewController:alert animated:YES completion:nil];

 UIAlertController *alert2 = [UIAlertController alertControllerWithTitle:@"Box 2" message:@"Second Block" preferredStyle:UIAlertControllerStyleAlert];
 [alert2 addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 [self presentViewController:alert2 animated:YES completion:nil];
}

What are the problems? Pay attention to the console, it will definitely output

Warning: Attempt to present <UIAlertController: 0x7ff4c3078c00>  on <SCTestViewController: 0x7ff4c2718c20> which is already presenting <UIAlertController: 0x7ff4c283ae00>

So, the second pop-up box should not be visible.

In another case, if it is a custom Alert, you add it as a subview of the window, and the second pop-up box will cover the first one. If you use a frosted glass background, the effect will be more obvious. It's definitely not suitable.

Therefore, the correct solution is a similar process to locking. When a button in the first pop-up box is clicked, the second pop-up box will pop up, so as to this kind of Rui.

Here, I thought of using semaphores to solve the problem, but semaphores will block the thread and cannot be used directly in the main thread. So we need to control the semaphore in the child thread, create and display Alert in the main thread, and directly upload the code.

- (void)viewDidAppear:(BOOL)animated {
 [super viewDidAppear:animated];
 //Create a queue, serial and parallel, mainly to operate the semaphore dispatch_queue_t queue = dispatch_queue_create("com.", DISPATCH_QUEUE_SERIAL);
 dispatch_async(queue, ^{
 //Create a semaphore with initial 0 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
 //The first pop-up box, the creation and display of UI must be in the main thread dispatch_async(dispatch_get_main_queue(), ^{
 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Box 1" message:@"First pop-up box" preferredStyle:UIAlertControllerStyleAlert];
 [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
 //Click the button on Alert and we send a signal once. dispatch_semaphore_signal(sema);
 }]];
 [self presentViewController:alert animated:YES completion:nil];
 });

 //Waiting for the signal to trigger, note that here is waiting in the queue we created dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
 //The above wait until the signal is triggered, then create a second Alert dispatch_async(dispatch_get_main_queue(), ^{
 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Box 2" message:@"Second Block" preferredStyle:UIAlertControllerStyleAlert];
 [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
 dispatch_semaphore_signal(sema);
 }]];
 [self presentViewController:alert animated:YES completion:nil];
 });

 //Similarly, create a third Alert dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
 dispatch_async(dispatch_get_main_queue(), ^{
 UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Box 3" message:@"Third Broadcast" preferredStyle:UIAlertControllerStyleAlert];
 [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
 dispatch_semaphore_signal(sema);
 }]];
 [self presentViewController:alert animated:YES completion:nil];
 });
 });
}

In this way, our needs are met.

It should be noted that why there is no global concurrent queue here, it is mainly because the semaphore will block the thread and the priority is particularly high. If there are still tasks in the queue at this time, then you will wait for the signal to trigger. Of course, some people do this on purpose. This requirement is very suitable for "don't do anything else when the pop-up box pops up". Of course we must not block the main thread!

We wait for signals in asynchronous threads and send signals in the main thread, so that the two threads can be synchronized. In fact, semaphore is a kind of lock.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.