简体   繁体   English

执行处理程序块时,UIAlertController为nil

[英]UIAlertController is nil when handler block executes

Here's the problem up front: I have a UIAlertController that has a textfield. 这是前面的问题:我有一个具有文本字段的UIAlertController。 I want to save the content of that textfield as an NSString when the user touches a "Confirm" button in the alert. 当用户触摸警报中的“确认”按钮时,我想将该文本字段的内容另存为NSString。 When the Confirm action block is executed, however, the alert is nil (presumably already dismissed and deallocated at that point), and thus so is its textfield, meaning I cannot save the textfield's text. 但是,当执行Confirm动作块时,警报为nil(大概已在该位置被取消并释放),因此其文本字段也是如此,这意味着我无法保存该文本字段的文本。

I am using a series of UIAlertControllers to allow a user to create a passcode for my app, such that any time the app comes to the foreground, the user is prompted for the code before the app can be used. 我正在使用一系列UIAlertControllers允许用户为我的应用程序创建密码,这样,每当应用程序出现在前台时,都会提示用户输入代码,然后才能使用该应用程序。

I created a category of UIAlertController with several convenience methods that return preconfigured alerts that I need to use. 我创建了带有多个便捷方法的UIAlertController类别,这些便捷方法返回了我需要使用的预配置警报。 Here's one of them: 这是其中之一:

+ (UIAlertController*)passcodeCreationAlertWithConfirmBehavior:(void(^)())confirmBlock andCancelBehavior:(void(^)())cancelBlock {
UIAlertController *passcodeCreationAlert = [UIAlertController alertControllerWithTitle:@"Enter a passcode"
                                                                               message:nil
                                                                        preferredStyle:UIAlertControllerStyleAlert];

[passcodeCreationAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.keyboardType = UIKeyboardTypeNumberPad;
}];

UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
                                                       style:UIAlertActionStyleCancel
                                                     handler:^(UIAlertAction * action) {
                                                         if (cancelBlock) {
                                                             cancelBlock();
                                                         }
                                                     }];

UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:@"Confirm"
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * action) {
                                                          if (confirmBlock) {
                                                              confirmBlock();
                                                          }
                                                      }];

[passcodeCreationAlert addAction:cancelAction];
[passcodeCreationAlert addAction:confirmAction];
passcodeCreationAlert.preferredAction = confirmAction;
confirmAction.enabled = NO;

return passcodeCreationAlert;
}

This method returns a UIAlertController that allows the user to enter their desired passcode into a textfield. 此方法返回一个UIAlertController,它允许用户在文本字段中输入所需的密码。 When I call this method in my view controller, I pass blocks as parameters which are used as the UIAlertAction handlers: 当我在视图控制器中调用此方法时,我将块作为参数传递给用作UIAlertAction处理程序的参数:

- (void)presentCreatePasscodeAlert {
UIAlertController *alert = [UIAlertController passcodeCreationAlertWithConfirmBehavior:^{
    firstPasscode = alert.textFields[0].text;
    [self presentConfirmPasscodeAlert];
} andCancelBehavior:^{
    [self presentEnablePasscodeAlert];
}];


alert.textFields[0].delegate = self;

[self presentViewController:alert animated:YES completion:nil];
}

To reiterate the problem now that there is more context: When the action block is entered at the line: 现在要重申这个问题,因为它有更多的上下文:在以下行中输入操作块时:

firstPasscode = alert.textFields[0].text;

the alert is nil, and so is its textfield, meaning I cannot save the textfield's text. 警报为零,其文本字段也为零,这意味着我无法保存该文本字段的文本。

In a separate project, however, I tried getting the same functionality without using the category and custom convenience methods, and that works as desired: 但是,在一个单独的项目中,我尝试在不使用类别和自定义便捷方法的情况下获得相同的功能,并且可以按需工作:

- (void) createPassword {
UIAlertController *createPasswordAlert = [UIAlertController alertControllerWithTitle:@"Enter a password"
                                                                             message:nil
                                                                      preferredStyle:UIAlertControllerStyleAlert];

__weak ViewController *weakSelf = self;

[createPasswordAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.delegate = weakSelf;
    textField.keyboardType = UIKeyboardTypeNumberPad;
}];


UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:@"Confirm"
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * action) {
                                                          self.password = createPasswordAlert.textFields[0].text;
                                                          [self confirmPassword];
                                                      }];

UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
                                                       style:UIAlertActionStyleDefault
                                                     handler:^(UIAlertAction * action) {
                                                         [self promptPasswordCreation];
                                                     }];

[createPasswordAlert addAction:confirmAction];
[createPasswordAlert addAction:cancelAction];

confirmAction.enabled = NO;

[self presentViewController:createPasswordAlert animated:YES completion:nil];
}

Sure enough, in the above code the alert exists when the Confirm block is entered, and I can save the text just fine. 可以肯定的是,在上面的代码中,当进入Confirm块时,存在警报,我可以保存文本了。

Have I done something screwy by passing blocks as parameters to my convenience methods? 通过将块作为参数传递给便捷方法,我是否做了一些棘手的事情?

One of your problems is that when you create the block and send it into the initializer you are referencing a nil object inside the block. 您的问题之一是,当您创建该块并将其发送到初始化程序时,您正在引用该块内的nil对象。 Then the block is saved with that nil reference and passed as a block to your handler. 然后,使用该nil引用保存该块,并将其作为块传递给您的处理程序。

UIAlertController *alert = [UIAlertController passcodeCreationAlertWithConfirmBehavior:^{
    firstPasscode = alert.textFields[0].text;
    [self presentConfirmPasscodeAlert];
} andCancelBehavior:^{
    [self presentEnablePasscodeAlert];
}];

In there alert is not initialized yet when you create that block and send it to be saved. 当您创建该块并将其发送以保存时, alert尚未初始化。 An option to fix that would be to use a standard initializer and then categorize a method to add the block functions that you want. 一种解决方法是使用标准的初始化程序,然后对方法进行分类以添加所需的块函数。 Another option might be to try to add the __block modifier to the alert object, although I don't think that will help. 另一个选择可能是尝试将__block修饰符添加到alert对象,尽管我认为这没有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM