リファクタリング中のプロジェクトで以下のようなクラスメソッドがあった。
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に置き換えようとスニペット的に
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を拾わなければいけない。
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 だけ別で拾おう。
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を拾うコードもこのアプリの中でよく使うので、こいつもクラスメソッド化
結果こうなりました。実際のコードには「メインスレッドから絶対に呼べや」ということで、メインスレッド判定などが入ってます。
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];
}