4
votes

I want to dismiss my UIAlertController with a click on the 'Cancel' button when my app goes in to background.

I've set up the background notification with

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

Then in my appDidEnterBackground function I have:

- (void)appDidEnterBackground {
    if (_alertController) {
        UIAlertAction *cancelAction = [[_alertController actions] objectAtIndex:0];

        //HERE: is there a way to trigger the cancelAction??

        [_alertController dismissViewControllerAnimated:NO completion:nil];
    }
}

What I'm struggling with is how to trigger the UIAlertAction programmatically. Is this possible?

2
I don't think you can programatically trigger the press of your UIAlertAction. You could try duplicating the code, or branching it off into a globally declared method? - MCKapur
@MCKapur Your second point has potential. I am already using a singleton for the UIAlertController (/UIAlertView for iOS7) so the actions are already getting defined globally. How would I store a block globally so I could call it when the app goes in to background? - CharlesA
@MCKapur that cracked it - I added a var to my singleton that saved the completion block action. Then I call this in appDidEnterBackground. If you post as an answer I'll accept. - CharlesA
Awesome, great to hear! It's fine - I don't really care, as long as you fixed your problem. - MCKapur

2 Answers

4
votes

I answered this with using the suggestion made by MCKapur.

I already had the UIAlertController in a singleton. What I did was define a variable in my singleton to save the completion action:

@property (copy, nonatomic) void (^completion)(BOOL);

Then when I set up the UIAlertController to show it, I also setup the completion code with:

_completion = ^(BOOL cancelled) {
    if (block) {
        block (NO, nil);
    }
};

Finally, I changed the appDidEnterBackground call to:

- (void)appDidEnterBackground {
    if (_alertController) {
        if (_completion) {
            _completion(NO);
            _completion = nil;
        }
        [_alertController dismissViewControllerAnimated:NO completion:nil];
    }
}
0
votes

This is old but it is the top result when looking for how to trigger a UIAlertAction programmatically.

Just in case anyone (still doing objC) is prepared to use internal methods - this works with iOS 10 and 11:

- (void)triggerAction:(UIAlertAction*)action onAlertController:(UIAlertController*)alert {
    SEL triggerSelector = NSSelectorFromString(@"_dismissAnimated:triggeringAction:triggeredByPopoverDimmingView:dismissCompletion:");
    NSMethodSignature* signature = [[alert class] instanceMethodSignatureForSelector:triggerSelector];
    if (!signature) {
        // Try pre iOS11 - OK as we're not trying to use the completion block
        triggerSelector = NSSelectorFromString(@"_dismissAnimated:triggeringAction:triggeredByPopoverDimmingView:");
        signature = [[alert class] instanceMethodSignatureForSelector:triggerSelector];
    }
    NSAssert(signature != nil, @"Couldn't find trigger method");
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:alert];
    [invocation setSelector:triggerSelector];
    BOOL boolValue = YES; // Animated & dimmingView
    [invocation setArgument:&boolValue atIndex:2];
    [invocation setArgument:&action atIndex:3];
    [invocation setArgument:&boolValue atIndex:4];
    // Not setting anything for the dismissCompletion block atIndex:5
    [invocation invoke];
}