How to get input string from UIAlertController in a synchronous method

Hi, My methodA is synchronous and be called in main thread. methodA gets input strings from methodB via poping a UIAlertController with UITextField. I have two versions of codes as below. On some iphones with iOS versions, both two versions codes works, such as iPhone SE2 with iOS 17.7. But on some iphones with iOS versions, the two versions of codes can't work, such as iPhone XR with iOS 18.0.1 or iPhone 14 plus with iOS 13.6. How can I get the input string from UIAlertController in the synchronous method on all iPhones and iOS versions.

/* //version 1. -(NSString *)methodA { // Prepare a local variable to capture the input __block NSString *inputString = nil;

// Call methodB to display the UIAlertController modally
[self methodBWithCompletion:^(NSString *result) {
    inputString = result;
    // Stop the run loop when input is received
    CFRunLoopStop(CFRunLoopGetCurrent());
}];

// Run the run loop manually to block execution until CFRunLoopStop() is called
CFRunLoopRun();

// Once the run loop stops, return the user input
return inputString;

}

-(void)methodBWithCompletion:(void (^)(NSString *))completion { // Create the UIAlertController for user input UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Enter PIN" message:nil preferredStyle:UIAlertControllerStyleAlert];

[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.placeholder = @"PIN";
    textField.secureTextEntry = YES;
}];

UIAlertAction *submitAction = [UIAlertAction actionWithTitle:@"Submit"
                                                       style:UIAlertActionStyleDefault
                                                     handler:^(UIAlertAction * _Nonnull action) {
    // Get the text from the UITextField
    UITextField *textField = alertController.textFields.firstObject;
    NSString *input = textField.text;
    
    // Pass the input back via the completion handler
    if (completion) {
        completion(input);
    }
}];

[alertController addAction:submitAction];

// Present the alert modally on the main window's rootViewController
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];

} */

/* //version 2. -(NSString *)methodA { // Prepare a variable to hold user input __block NSString *inputString = nil;

NSLog(@"methodA:....");
// Call methodB to display the UIAlertController asynchronously
[self methodBWithCompletion:^(NSString *result) {
    inputString = result;
}];

// Run the main run loop until the inputString is not nil (user input provided)
while (inputString == nil) {
    // Run the loop for a short time interval, allowing the UI to remain responsive
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}

// Return the input string once the user has submitted the input
return inputString;

}

-(void)methodBWithCompletion:(void (^)(NSString *))completion { // Create and configure the UIAlertController UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Enter PIN" message:nil preferredStyle:UIAlertControllerStyleAlert];

[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.placeholder = @"PIN";
    textField.secureTextEntry = YES;
}];

UIAlertAction *submitAction = [UIAlertAction actionWithTitle:@"Submit"
                                                       style:UIAlertActionStyleDefault
                                                     handler:^(UIAlertAction * _Nonnull action) {
    UITextField *textField = alertController.textFields.firstObject;
    NSString *input = textField.text;

    // Return the input via the completion handler
    if (completion) {
        completion(input);
    }
}];

[alertController addAction:submitAction];

// Present the alert on the main thread
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];

} */

Answered by Frameworks Engineer in 811629022

What you are attempting has never been supported – it is undefined what happens when you spin the run loop like you are doing, and in this case different device behave differently in ways such that on some devices the alert will present and not on others.

In general on Apple platforms, there are no provisions for forcing the UI to operate in a "synchronous" mode like you are trying to do.

The UIAlertController doesn't popup on iPhone XR with iOS 18.0.1 and iPhone 14 plus with iOS 13.6. But the UIAlertController will popup correctly and accept input string on iPhone SE with iOS 17.7. Why is there such a big compatibility issue.

What you are attempting has never been supported – it is undefined what happens when you spin the run loop like you are doing, and in this case different device behave differently in ways such that on some devices the alert will present and not on others.

In general on Apple platforms, there are no provisions for forcing the UI to operate in a "synchronous" mode like you are trying to do.

How to get input string from UIAlertController in a synchronous method
 
 
Q