はじめに
久しぶりにのObjective-Cの投稿です。
今回は、UIAlertControllerでTextField付きのAlertを表示する処理を
UIViewControllerのクラス拡張として実装してみました。
AlertにTextFieldを付ける方法は、@d-kawahara さんの
アラートコントローラーにテキストフィールドを入れる
が参考になります。
やること
- AlertにTextFieldを付ける
- TextFieldに文字が入力されたり、消されたら、通知する
- TextFieldの入力文字数が0の場合、AlertのOKボタンを無効にする
- OKボタンを押したら、入力した文字列をLabelに表示する
TextField付きのAlertを表示する処理
UIViewController+Alert.h
# import <UIKit/UIKit.h>
# import <objc/runtime.h>
typedef void (^OKActionHandler)(NSString *outputText);
@interface UIViewController (Alert)
@property (nonatomic) UIAlertController *alertWithTextfield;
- (void)showAlertWithTextfield:(NSString *)defaultText
placeholder:(NSString *)placeholder
alertTitle:(NSString *)alertTitle
alertMessage:(NSString *)alertMessage
textFieldTextDidChange:(SEL)aSelector
okActionHandler:(OKActionHandler)okActionHandler;
@end
UIViewController+Alert.m
# import "UIViewController+Alert.h"
typedef void (^AlertActionHandler)(UIAlertAction *action);
@implementation UIViewController (Alert)
const void *alertWithTextfieldKey = @"alertWithTextfield";
@dynamic alertWithTextfield;
# pragma mark - Setter
- (void)setAlertWithTextfield:(UIAlertController *)alertWithTextfield {
objc_setAssociatedObject(self,
alertWithTextfieldKey,
alertWithTextfield,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
# pragma mark - Getter
- (UIAlertController *)alertWithTextfield {
return objc_getAssociatedObject(self,
alertWithTextfieldKey);
}
# pragma mark - Category Methods
- (void)showAlertWithTextfield:(NSString *)defaultText
placeholder:(NSString *)placeholder
alertTitle:(NSString *)alertTitle
alertMessage:(NSString *)alertMessage
textFieldTextDidChange:(SEL)aSelector
okActionHandler:(OKActionHandler)okActionHandler {
self.alertWithTextfield = [UIAlertController alertControllerWithTitle:alertTitle
message:alertMessage
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[self.alertWithTextfield addTextFieldWithConfigurationHandler:^(UITextField *textField) {
__strong typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
textField.placeholder = placeholder;
textField.text = defaultText;
// TextFieldに通知を登録
[NSNotificationCenter.defaultCenter addObserver:strongSelf
selector:aSelector
name:UITextFieldTextDidChangeNotification
object:textField];
}];
// OKタップ時の処理
AlertActionHandler okHandler = ^(UIAlertAction *action) {
__strong typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
UITextField *alertTextField = strongSelf.alertWithTextfield.textFields.firstObject;
okActionHandler(alertTextField.text);
[NSNotificationCenter.defaultCenter removeObserver:alertTextField];
};
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:okHandler];
// キャンセルタップ時の処理
AlertActionHandler cancelHandler = ^(UIAlertAction *action) {
__strong typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
UITextField *alertTextField = strongSelf.alertWithTextfield.textFields.firstObject;
// TextFieldに登録した通知を削除
[NSNotificationCenter.defaultCenter removeObserver:alertTextField];
};
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"キャンセル"
style:UIAlertActionStyleCancel
handler:cancelHandler];
// 引数のtextの長さによって、OKボタンの初期状態を設定
BOOL enabledOKButton = defaultText && defaultText.length > 0;
okAction.enabled = enabledOKButton;
[self.alertWithTextfield addAction:cancelAction];
[self.alertWithTextfield addAction:okAction];
[self presentViewController:self.alertWithTextfield animated:YES completion:nil];
}
@end
ViewControllerで呼び出す
ViewController.m
# import "ViewController.h"
# import "UIViewController+Alert.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *outputLabel;
@end
@implementation ViewController
# pragma mark - View Life Cycle
- (void)viewDidLoad {
[super viewDidLoad];
}
# pragma mark - IBActions
/**
Show Alertボタンがタップされた時の処理
*/
- (IBAction)didTapShowAlertButton:(UIButton *)sender {
__weak typeof(self) weakSelf = self;
[self showAlertWithTextfield:self.outputLabel.text
placeholder:@"テキストを入力してください。"
alertTitle:@"たいとる"
alertMessage:@"めっせーじ"
textFieldTextDidChange:@selector(alertTextFieldTextDidChange:)
okActionHandler:^(NSString *outputText) {
// AlertのTextFieldで入力された文字をoutputLabelに表示
weakSelf.outputLabel.text = outputText;
}];
}
# pragma mark - Selector
/**
Alert内のTextFieldの文字が変更された時に呼ばれるセレクタメソッド
*/
- (void)alertTextFieldTextDidChange:(NSNotification *)notification {
UITextField *textField = notification.object;
// 入力後の文字数が0より大きければ、AlertのOKボタン有効
// 0文字の場合は、AlertのOKボタン無効
NSUInteger textLength = textField.text.length;
BOOL enabledAlertOKButton = textLength > 0;
self.alertWithTextfield.actions.lastObject.enabled = enabledAlertOKButton;
}
@end
動作
さいごに
Categoryは少しコードが長くなってしまいましたが、ViewController側の実装が簡単になりました。
また、Categoryに書くことによって他のクラスでも使いまわせるようになりました。
本記事で紹介したコードは、Githubにあげています。
ios-objc-uialertcontroller-uitextfield-demo