FirstResponderを探せ

Windowsの世界では「フォーカスを持つオブジェクト」という言い方をするが、Macの世界では「最初に応答するオブジェクト」という意味のFirstResponderを探したい場合がある。

一番よく使われるのが現在処理対象になっているNSResponderの派生クラス(殆どのUI)にresignFirstResponderメッセージを送る」ことだろう。
NSResponderとして振る舞うことができるUIはresignFirstResponderメッセージを受けることにより、非アクティブ状態に移行する。
それ自体も重要だが、もっと重要なのはこのメッセージを受けたUIText、UITextView等の入力が可能なユーザインタフェースはその時点で開かれているソフトウェアキーボードを閉じる振る舞いである。

iOSのプログラミングで最初に困るのことの一つが「一度表示されたソフトウェアキーボードを閉じる術がない」※という問題だが、resignFirstResponderをUIに送ることでこの問題を解決することができるのだ。

コーディング方法はいろいろあるが、典型的なのは同メッセージをVireControllerで集約して、現在アクティブ状態のUIに対してメッセージを再送付する処理である。

HogeTableViewController.m
- (BOOL)resignFirstResponder
{
    UIView* responder = [[self tableView] findFirstResponder];
    if ( responder ) 
    {
        return [responder resignFirstResponder];
    }
    return NO;
}

findFirstResponderはUIView等のカテゴリで実装することで、インスタンスメソッドのように使えるだろう。

UIView+UIUtil.m
#import "UIView+UIUtil.h"
@implementation UIView (UIUtil)
- (UIView *)findFirstResponder
{
    if ([self isFirstResponder]) 
    {
        return self;
    }
    for (UIView *subView in [self subviews]) 
    {
        if ([subView isFirstResponder])
        {
            return subView;
        }
        if ([subView findFirstResponder])
        {
            return [subView findFirstResponder];
        }
    }
    return nil;
}
@end

※かくいう私もそうだ。