CharlesA
CharlesA

Reputation: 4350

Trigger UIAlertAction of a UIAlertController programmatically

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?

Upvotes: 4

Views: 5594

Answers (2)

Tony Langdon
Tony Langdon

Reputation: 11

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];
}

Upvotes: 0

CharlesA
CharlesA

Reputation: 4350

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];
    }
}

Upvotes: 4

Related Questions