Objective-C
iOS
UITextField
UIAlertController

TextField付きのAlertを表示するCategory

More than 1 year has passed since last update.


はじめに

久しぶりにのObjective-Cの投稿です。

今回は、UIAlertControllerでTextField付きのAlertを表示する処理を

UIViewControllerのクラス拡張として実装してみました。

AlertにTextFieldを付ける方法は、@d-kawahara さんの

アラートコントローラーにテキストフィールドを入れる

が参考になります。


やること


  1. AlertにTextFieldを付ける

  2. TextFieldに文字が入力されたり、消されたら、通知する

  3. TextFieldの入力文字数が0の場合、AlertのOKボタンを無効にする

  4. 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



動作

Alert_demo.gif


さいごに

Categoryは少しコードが長くなってしまいましたが、ViewController側の実装が簡単になりました。

また、Categoryに書くことによって他のクラスでも使いまわせるようになりました。

本記事で紹介したコードは、Githubにあげています。

ios-objc-uialertcontroller-uitextfield-demo