NSViewにNSTextInputを実装し、さらにNSLayoutManagerなどを併用することで、テキストの編集ができるようになりました。しかし、このようにして作られたビューはとても重量級のオブジェクトとなります。一つのウインドウ内にテキスト編集可能なフィールドを沢山配置すると、必要以上にメモリを消費して、パフォーマンスに大きな影響が出るかもしれません。
Cocoaには、これに対する対策として、フィールドエディターというものが用意されています。テキストの編集はファーストレスポンダにならないとできないため、テキストを編集しているビューはウインドウ内に同時に1つしか存在できません。この特性を利用して、ウインドウ内に配置されている複数のビューの間で、1つのテキストビューを共有すれば、パフォーマンスを改善することができます。このとき、ウインドウ内で共有されるテキストビューが、フィールドエディターです。
フィールドエディターはNSTextViewクラスのオブジェクトで、NSWindowが管理しています。フィールドエディターを利用しようとするビューは、自身が置かれているNSWindowに対して、fieldEditor:forObject:メソッドを呼び出して、フィールドエディターを取得します。
NSWindow* window = [self window]; [window endEditingFor:self]; NSTextView* fieldEditer; fieldEditer = (NSTextView*)[window fieldEditor:YES forObject:self];
fieldEditor:forObject:の第一引数は、新規にフィールドエディターを生成するかどうかです。しかし、NSWindowはフィールドエディターを一つしか生成しないので、2回目以降のメソッド呼び出しで引数をYESにしても、1回目のときと同じオブジェクトが返されます。第二引数は、フィールドエディターを使おうとしているオブジェクト、つまり自分自身を渡します。
ただ、この操作によってフィールドエディターを占有することはできません。自身がフィールドエディターを使用してる最中に、別のビューがフィールドエディターを取得するかもしれません。また、自身がフィールドエディターを取得しようとしたとき、既に別のビューがフィールドエディターを使用しているかもしれません。
そのため上記の例では、最初にendEditingFor:メソッドを呼んで、フィールドエディターが現在使用中であれば、強制的に使用を中止させてます。
fieldEditor:forObject:は、クラスリファレンスではNSTextを返すことになっていますが、実際にはNSTextViewを返します。返ってきたNSTextViewは、fieldEditorプロパティーがYESになっているため、タブやリターンを入力すると編集が終了するようになっていますが、それ以外は普通のNSTextViewです。
フィールドエディターを取得したら、それを自身のビューの手前に重ね置きして、テキストの編集作業を全て委ねます。テキストの編集が完了したら、その結果だけを自身のビューに反映させて、フィールドエディターを撤去すれば、一連の操作が完了します。
なお、NSTextView単体だと大量に文字を入力したときに、ビューのエリア外に文字が溢れてしまうので、実際にはNSClipViewを併用して、このような時にビューがスクロールするようにします。