升级到 iOS 11.3 破坏了 __weak UIAlertAction

upgrade to iOS 11.3 broke __weak UIAlertAction

昨天我将 iPhone 6s 更新为 iOS 11.3。当我打开我的应用程序时,它立即崩溃了。我追踪到以下代码的崩溃,我发现我的 'yes' UIAlertAction 为 nil。

即使在我取出 __weak 声明后,代码仍会运行并且不会崩溃,但是我的警报不会像以前那样在屏幕上弹出。我到处都使用了其中的几个警报。

我的代码有问题吗?或者这是一个合法的 11.3 iOS 错误? 更新到 11.3 后是否有其他人遇到过类似的崩溃? 此代码在 1.5 年内一直运行良好,最近没有 变化。

- (void) alertGotoAppSettings:(NSString *)title :(NSString *)msg :(UIViewController *)view
{
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
                                                                    message:msg
                                                             preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction __weak *yes = [UIAlertAction
                         actionWithTitle:LOC(@"Yes")
                         style:UIAlertActionStyleDefault
                         handler:^(UIAlertAction * action)
                         {
                             // Launch Settings for GPS
                             if (UIApplicationOpenSettingsURLString != nil) {
                                 NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
                                 if (IS_IOS_10_OR_LATER) {
                                     [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success)
                                      {
                                      }];
                                 }
                                 else {
                                     [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
                                 }
                             }
                         }];

    UIAlertAction __weak *no = [UIAlertAction
                         actionWithTitle:LOC(@"No")
                         style:UIAlertActionStyleCancel
                         handler:^(UIAlertAction * action)
                         {
                             dispatch_async(dispatch_get_main_queue(), ^{
                                 [alert dismissViewControllerAnimated:YES completion:nil];
                             });
                         }];

    [alert addAction:no];
    [alert addAction:yes]; <---- 'yes' is nil here

    UIAlertController __weak *weakAlert = alert;
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertController *strongAlert = weakAlert;
        [view presentViewController:strongAlert animated:YES completion:nil];
    });
}

yesno 都不应该是 __weak。同样,应该从此代码片段中删除 weakAlert/strongAlert 模式。

仅当相关对象具有其他显式强引用时才应使用弱引用,但您只是不希望您的代码建立另一个强引用。特别是,当存在强引用循环的风险时,您可以使用 weak。但是这里不存在这种潜在的强引用循环。坦率地说,在不涉及其他显式强引用的情况下,将 weak 与局部变量结合使用根本没有意义。

底线,weak 表示 "this object can be deallocated and this particular reference can be set to nil when there are no strong references remaining"。但在这种情况下,由于您唯一的参考是 weak 参考,因此没有任何强参考。因此,ARC 可以自由地释放它们。

有问题的代码可能在过去有效(也许 ARC 对于何时释放对象更为保守),但在这种情况下删除这些 weak 引用是正确的。它们毫无用处,并且使对象的范围变得模糊。