0

I'm trying to implement a method alertAndWait that should work when called from main thread "directly" and when dispatched like this:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    dispatch_sync(dispatch_get_main_queue(), ^{
        call alertAndWait
...

When alertAndWait is called an alert window opens and the current thread is (non-busy) waiting. When the OK button is pressed the alert dissapears and the current thread does continue.

My "solution" doesn't really work correctly. I know the reason: there is a deadlock caused by parallel dispatch_sync - blocks ... but i don't know how to prevent it ...

- (void)viewDidAppear:(BOOL)animated {

    // called from main thread
    NSLog(@"Step 1");
    [self alertAndWait];
    NSLog(@"Step 4");

    // called from background thread
    NSLog(@"Step 1");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        dispatch_sync(dispatch_get_main_queue(), ^{
            [self alertAndWait];
             NSLog(@"Step 4");
        });
    });
}

- (void)alertAndWait {
        NSLog(@"Step 2");
        __block BOOL ok = NO;
        UIAlertController* myAlert = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                         message:@"Please press OK to continue"
                                                                  preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                               handler:^(UIAlertAction * action) {
                                                                   ok=YES;
                                                               }];
        [myAlert addAction:continueAction];
        [self presentViewController:myAlert animated:NO completion:nil];
        while(!ok) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        };
        NSLog(@"Step 3");
}

Expected output is like this:

AlertNWait[9879:164395] Step 1
AlertNWait[9879:164395] Step 2
AlertNWait[9879:164395] Step 3
AlertNWait[9879:164395] Step 4
AlertNWait[9879:164395] Step 1
AlertNWait[9879:164395] Step 2
AlertNWait[9879:164395] Step 3
AlertNWait[9879:164395] Step 4

After Step 2 the alert opens and Step 3 follows when the user presses the OK button.

But now the log ends after "Step 2" when OK was pressed (the second time):

AlertNWait[9879:164395] Step 1
AlertNWait[9879:164395] Step 2
AlertNWait[9879:164395] Step 3
AlertNWait[9879:164395] Step 4
AlertNWait[9879:164395] Step 1
AlertNWait[9879:164395] Step 2

I've uploaded the Xcode project to github for your convenience.

Is there a way to make alertAndWait working as required? Thank You!

1 Answers1

0

You cannot wait in this case, but you can pass a completion block to alertAndWait to be executed after the alert is dismissed.

- (void)viewDidAppear:(BOOL)animated {
    // called from main thread
    NSLog(@"Step 1");
    [self alertAndWait:^() {
        // do whatever you want here
    }];
    NSLog(@"Step 4");
}

- (void)alertAndWait:(void (^)())block {
    UIAlertController* myAlert = ...
    ...
    [self presentViewController:myAlert animated:NO completion:block];
    ...
}
Marcos Crispino
  • 8,018
  • 5
  • 41
  • 59
  • Thank you. I know about completion blocks. But what I'm searching for is alertAndWait exactly as mentioned before. The alertAndWait is working when it is called from main thread but not when "dispatched" from background thread: dispatch_sync(dispatch_get_main_queue(), ^{ call alertAndWait ... . –  Mar 10 '16 at 06:10