バインディングした値の表示形式を変えたい。Value Transformer を使ってみることにした。まずは動作を確認するためにサンプルを作ってみる。
VTSample.zip
すべて同じモデル(値)とバインディングされている。上は 10進数での入力・表示する。下は NSValueTransformerを使い同じ値を 16進数で入力・表示させる。
NSValueTransformerの使い方は ADCに書かれている。
Value Transformer Programming Guide
これに沿ってコーディングしていく。
まずはヘッダファイル。NSValueTransformerのサブクラスを作る。
HexValueTransformer.h
@interface HexValueTransformer : NSValueTransformer {
}
@end
そして実装。
HexValueTransformer.m
まず変換後のオブジェクトのクラス型を定義する。
+ (Class)transformedValueClass
{
return [NSString class];
}
そして変換コード。ここでは入力値(NSNumber)を 16進数文字列として返す。これが表示で使われる。
- (id)transformedValue:(id)value
{
NSString* hex_value = [NSString stringWithFormat:@"%x", [value intValue]];
return hex_value;
}
続いて入力された値の変換。まず #allowsReverseTransformation をオーバライドして YESを返す。
+ (BOOL)allowsReverseTransformation
{
return YES;
}
そして入力値の変換コードを書く。簡易的な16進数文字列->NSNumber 変換コードを書いてみた。
- (id)reverseTransformedValue:(id)value
{
int num = 0;
int x =1;
int i = 0;
unichar ch;
for (i=[value length]-1; i >= 0; i--) {
ch = [value characterAtIndex:i];
if ('0' <= ch && ch <= '9') {
num += x * (ch - '0');
} else if ('a' <= ch && ch <= 'f') {
num += x * (ch - 'a' + 10);
} else if ('A' <= ch && ch <= 'F') {
num += x * (ch - 'A' + 10);
}
x *= 16;
}
return [NSNumber numberWithInt:num];
}
これで準備ができた。この他に2つほど行なうことがある。
1つめは変換クラスのインスタンスの登録。ADCのドキュメントによれば、通常はアプリケーションのデリゲートクラスの初期化コードで行なうとのこと。サンプルではコントローラクラスに下記のようなコードを書いた。
MyController.m
static BOOL initialized = NO;
+(void)initialize
{
if (!initialized) {
HexValueTransformer *transformer = [[[HexValueTransformer alloc] init] autorelease];
[NSValueTransformer setValueTransformer:transformer
forName:@"HexValueTransformer"];
initialized = YES;
}
}
forName: で指定する名前はバインディングで指定する時に使う。通常はクラス名で良い。ADCによれば名前を替えることで同じクラスの複数のインスタンスを登録できるようだ。そうであれば変換クラスをいくつも用意するのではなく、一つにまとめることもできそう。
そしてもう一つはバインディングでの指定。Interface Builderを使い 16進数入出力に使うテキストフィールドとラベルにこのクラスを指定する。
これでできあがり。
- - - -
これで目的は達成できそうだが、今回のような表現変換は NSValueTransformer の想定する用途とはちょっと異なる気もする。