NSTextFieldの文字数制限を行う


概要

  • NSTextFieldの入力文字数に制限をかけたい。
  • 今回は2種類を試す。1つはNSTextField、もう1つはNSFormatterのカスタムクラスを作ること。

GitHub

方法1_NSTextFieldのカスタムクラスを作成する

実装

FirstWindowTextField.m
#import "FirstWindowTextField.h"

static const NSUInteger kCharLimit = 5; // 文字数制限

@interface FirstWindowTextField() <NSTextFieldDelegate>
@end

@implementation FirstWindowTextField

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    // Drawing code here.
}

- (id) initWithCoder:(NSCoder *)decoder
{
    self = [super initWithCoder:decoder];
    if (self) {
        [self setDelegate: self];
    }
    return self;
}

// MARK:- NSTextFieldDelegate(実際はNSControl由来) Methods
- (void)controlTextDidChange:(NSNotification *)aNotification {
    NSString *newString = [self stringValue];
    if ([newString length] > kCharLimit) {
        [self setStringValue:[newString substringToIndex:kCharLimit]];
    }
}

@end
  • NSTextFieldのサブクラスを作成し、xib側でNSTextFieldのクラスに指定。
  • NSTextFieldDelegate(実際はNSControlのDelegate由来)のメソッドを用いて、テキストが入力される毎に呼ばれるメソッドを利用して文字数制限を行う。
  • 入力後の文字数が制限をオーバーしていた場合、substringToIndex:kCharLimitで前から制限文字数を抜き出している。
controlTextDidChange:(NSNotification *)aNotification;

方法2_NSFormatterのカスタムクラスを作成する

参考

実装(コード)

  • NSFormatterのカスタムクラス、CustomTextFieldFormatterを作成する。
//  CustomTextFieldFormatter.m
//  TextFieldWithCharacterNumberLimit

#import "CustomTextFieldFormatter.h"

@interface CustomTextFieldFormatter ()
@property NSUInteger charLimit; // 制限文字数
@end

@implementation CustomTextFieldFormatter
- (id)init {
    if(self = [super init]){
        [self setCharLimit:3];
    }
    return self;
}

/**
 @brief 部分文字列が有効かどうか - ユーザがキーを押す際に呼ばれる
 @param partialString 現在セル内にあるテキスト
 @param newString partialStringの変更が必要なときの置換文字列
 @return 部分文字列が有効かどうか
 */
- (BOOL)isPartialStringValid:(NSString *)partialString
            newEditingString:(NSString **)newString
            errorDescription:(NSString **)error {
    if ((int)[partialString length] > _charLimit) {
        *newString = [partialString substringToIndex:_charLimit];
        return NO;  // newStringでpartialStringを置換
    }
    return YES;
}

// MARK:- NSFormatter Methods
// NSFormatterのカスタムクラス作成に必須なメソッド

/**
 @brief セルのオブジェクトを文字列表現に変換(数値→文字列)
 */
- (NSString *)stringForObjectValue:(id)object {
    return (NSString *)object;
}

/**
 @brief 文字列をセルに関連付けられたオブジェクトに変換(文字列→数値)
 */
- (BOOL)getObjectValue:(id *)object
             forString:(NSString *)string
      errorDescription:(NSString **)error {
    *object = string;
    return YES;
}
@end
  • 下記はユーザがキーを押す際に呼ばれるメソッドで、部分文字列が有効かどうかを返す。
  • やっていることは方法1と同じように、制限文字数より多い場合、newStringに制限文字数の文字列を代入している。
/**
 @brief 部分文字列が有効かどうか - ユーザがキーを押す際に呼ばれる
 @param partialString 現在セル内にあるテキスト
 @param newString partialStringの変更が必要なときの置換文字列
 @return 部分文字列が有効かどうか
 */
- (BOOL)isPartialStringValid:(NSString *)partialString
            newEditingString:(NSString **)newString
            errorDescription:(NSString **)error {
    if ((int)[partialString length] > _charLimit) {
        *newString = [partialString substringToIndex:_charLimit];
        return NO;  // newStringでpartialStringを置換
    }
    return YES;
}

  • 下記はNSFormatterのカスタムクラスを作成する際にoverrideが必要なメソッド。
// MARK:- NSFormatter Methods
// NSFormatterのカスタムクラス作成に必須なメソッド
/**
 @brief セルのオブジェクトを文字列表現に変換(数値→文字列)
 */
- (NSString *)stringForObjectValue:(id)object {
    return (NSString *)object;
}

/**
 @brief 文字列をセルに関連付けられたオブジェクトに変換(文字列→数値)
 */
- (BOOL)getObjectValue:(id *)object
             forString:(NSString *)string
      errorDescription:(NSString **)error {
    *object = string;
    return YES;
}

実装(xib側)

  • オブジェクトを挿入して、クラスをCustomTextFieldFormatterとする。

  • フォーマッタにカスタムしたものを設定

課題

/**
 @brief 無効な文字を入力しないようにする
 @param partialStringPtr 検証する新しい文字列
 @param proposedSelRangePtr 文字列が受け入れられるか置き換えられる場合に使用される選択範囲。
 @param origString 変更が提案される前の元の文字列。
 @param origSelRange 変更が行われる選択範囲。
 */
- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
              originalString:(NSString *)origString
       originalSelectedRange:(NSRange)origSelRange
            errorDescription:(NSString **)error {
    int size = (int)[*partialStringPtr length];
    if (size > _charLimit) {
        return NO;
    }
    return YES;
}