【问题标题】:UIAlertController is nil when handler block executes处理程序块执行时 UIAlertController 为 nil
【发布时间】:2016-01-04 19:28:51
【问题描述】:

这是前面的问题:我有一个 UIAlertController,它有一个文本字段。当用户触摸警报中的“确认”按钮时,我想将该文本字段的内容保存为 NSString。但是,当执行 Confirm 操作块时,警报为 nil(可能此时已经解除并释放),因此它的文本字段也是如此,这意味着我无法保存文本字段的文本。

我正在使用一系列 UIAlertController 来允许用户为我的应用创建密码,这样每当应用进入前台时,都会提示用户输入密码,然后才能使用应用。

我创建了一个 UIAlertController 类别,其中包含几个返回我需要使用的预配置警报的便捷方法。这是其中之一:

+ (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;
}

此方法返回一个 UIAlertController,允许用户在文本字段中输入所需的密码。当我在视图控制器中调用此方法时,我将块作为参数传递给 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];
}

现在有更多的上下文来重申这个问题:当在该行输入操作块时:

firstPasscode = alert.textFields[0].text;

警报为零,它的文本字段也是如此,这意味着我无法保存文本字段的文本。

然而,在一个单独的项目中,我尝试在不使用类别和自定义便捷方法的情况下获得相同的功能,并且可以按预期工作:

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

果然,在上面的代码中,当输入确认块时,警报就存在了,我可以保存文本就好了。

通过将块作为参数传递给我的便捷方法,我做了什么奇怪的事情吗?

【问题讨论】:

    标签: ios objective-c iphone objective-c-blocks uialertcontroller


    【解决方案1】:

    您的一个问题是,当您创建块并将其发送到初始化程序时,您正在引用块内的 nil 对象。然后将该块与 nil 引用一起保存并作为块传递给您的处理程序。

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

    当您创建该块并将其发送以进行保存时,alert 尚未初始化。解决此问题的一个选项是使用标准初始化程序,然后对方法进行分类以添加所需的块函数。另一种选择可能是尝试将__block 修饰符添加到alert 对象,尽管我认为这不会有帮助。

    【讨论】:

    • 在帮助下用__block装饰alert,因为在创建块时不再捕获变量,并且正确地获取了它的值。
    • @Cristik 在大年初一之后用__blocks 装饰不是失礼吗?
    • 这仅适用于平分年份,希望 2016 年不是其中之一。
    • 您说的完全正确,非常感谢。使用带有警报的 __block 修饰符就可以了,但是据我所知,使用单独的方法来传递块是另一个完全可行的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 2020-08-07
    • 1970-01-01
    • 2023-01-29
    • 1970-01-01
    相关资源
    最近更新 更多