[Objective-C]今更UIAlertViewをUIAlertControllerに置き換えようとしてめんどくさいことにハマったので爪痕を残す

リファクタリング中のプロジェクトで以下のようなクラスメソッドがあった。

```objc:utility.m
+ (void)alertWithTitle:(NSString *)title
               message:(NSString *)message
           buttonTilte:(NSString *)buttonTitle
{
    [[[UIAlertView alloc] initWithTitle:title
                                message:message
                               delegate:nil
                      cancelButtonTitle:buttonTitle
                      otherButtonTitles:nil] show];
}
```

おう、今更懐かしのUIAlertViewかよ。ってことで、UIAlertControllerに置き換えようとスニペット的に

```objc:Utility.m
+ (void)alertWithTitle:(NSString *)title
               message:(NSString *)message
           buttonTilte:(NSString *)buttonTitle
{
      UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
      UIAlertAction *cancelButtonAction = [UIAlertAction actionWithTitle:buttonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}];
      [alertController addAction:cancelButtonAction];
      [self presentViewController:alertController animated:YES completion:nil];
}

```

と書きかけて、ふと困った。これ、ユーティリティ関数のクラスメソッドなので、selfはUIViewControllerではない。
どこから呼び出されるかわからないので、現在表示してるUIViewControllerを拾わなければいけない。

```objc:Utility.m
+ (void)alertWithTitle:(NSString *)title
               message:(NSString *)message
           buttonTilte:(NSString *)buttonTitle
{
      UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
      UIAlertAction *cancelButtonAction = [UIAlertAction actionWithTitle:buttonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}];
      [alertController addAction:cancelButtonAction];
      UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

      while (topController.presentedViewController) {
          topController = topController.presentedViewController;
      }
      [topController presentViewController:alertController animated:YES completion:nil];
}

```

と、今度は、keyWindowはiOS13以降deprecatedだ！　今はUIScene でマルチウィンドウな対応が求められることがある。
といっても、このアプリはUIApplicationDelegateバリバリ採用のレガシーアプリだから、影響はない。
けど気持ち悪い。

なので、keywindow だけ別で拾おう。

https://stackoverflow.com/questions/57134259/how-to-resolve-keywindow-was-deprecated-in-ios-13-0/57899013
から、コードを拝借

```objc:Utility.m
+(UIWindow*)keyWindow
{
    UIWindow        *foundWindow = nil;
    NSArray         *windows = [[UIApplication sharedApplication]windows];
    for (UIWindow   *window in windows) {
        if (window.isKeyWindow) {
            foundWindow = window;
            break;
        }
    }
    return foundWindow;
}
```

これをUtility.mに追加。

ついでに、表示中のUIViewControllerを拾うコードもこのアプリの中でよく使うので、こいつもクラスメソッド化

結果こうなりました。実際のコードには「メインスレッドから絶対に呼べや」ということで、メインスレッド判定などが入ってます。

```objc:Utility.m

+ (void)alertOnMainThreadWithTitle:(NSString *)title
                           message:(NSString *)message
                       buttonTilte:(NSString *)buttonTitle
{
      UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
      UIAlertAction *cancelButtonAction = [UIAlertAction actionWithTitle:buttonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}];
      [alertController addAction:cancelButtonAction];
      [[Utility topController] presentViewController:alertController animated:YES completion:nil];
}

```