独自のValueTransformerを作って、Bindingで自由に値変換する方法

以前、NSColorをファイルに保存するために利用したValueTransformerはとても便利な機能だった。NSUnarchiveFromDataという変換方法を指定するだけの手軽さで、ファイルへの保存が可能になった。他にもいくつかの変換方法がデフォルトで用意されているが、やはり独自の変換方法も設定したくなるのが自然な欲求だ。その方法は、ちゃんと用意されていた。以下のような手順だ。試しにNSColorを、RGBの輝度情報の文字列に変換してみた。

独自の変換をNSValueTransformerのサブクラスに定義する

  • NSValueTransformerのサブクラスでは、二つのクラスメソッドと一つのインスタンスメソッドを必ず定義する必要がある。
    • +(Class) transformedValueClass;
    • +(BOOL) allowsReverseTransformation;
    • - (id)transformedValue:(id)value;
  • 双方向の変換(モデルからビュ、ビューからモデル)をサポートする場合は、さらにもう一つインスタンスメソッドを定義する。
    • - (id)reverseTransformedValue:(id)value;
  • もし、双方向の変換がサポートされない場合、モデルからビューのデータの流れのみとなり、そのビューは表示専用(編集不可)の状態になる。
//---------- ColorToRgbTransformer.h ----------
#import <Cocoa/Cocoa.h>


@interface ColorToRgbTransformer : NSValueTransformer {

}

@end
//---------- ColorToRgbTransformer.m ----------
#import "ColorToRgbTransformer.h"


@implementation ColorToColorNameTransformer

// (必須)変換後のクラスを返す
+(Class) transformedValueClass {
    return [NSString class];
}

// (必須)逆変換が可能かどうか?
// YESを返すなら、reverseTransformedValue:の実装が必要
// NOを返すなら、そのビューは編集不可の状態になる
+(BOOL) allowsReverseTransformation {
    return YES;
}

// (必須)変換して返す(モデル >> ビュー変換)
- (id)transformedValue:(id)value {
    float ^K r, g, b, a;
    [value getRed:&r green:&g blue:&b alpha:&a ];
    
    return [NSString stringWithFormat:@"(R, G, B, Alpha)=(%.0f%%, %.0f%%, %.0f%%, %.0f%%)",
                                      r * 100, g * 100, b * 100, a * 100];
}

// 逆変換して返す(ビュー >> モデル変換)
// allowsReverseTransformationがYESを返す時に必要
- (id)reverseTransformedValue:(id)value {
    return nil;
}

@end

定義したクラスをインスタンス化して登録する

  • 独自の値変換クラス ColorToRgbTransformer は、アプリケーションのデリゲートメソッド applicationDidFinishLaunching: の中で登録するのがお勧めのようだ。
    • そのため、アプリケーションのデリゲートを処理するためのAppControllerを追加した。
    • 独自のValueTransformerクラスはインスタンス化して、autoReleaseして登録する。
    • forName:はInterface Builderの Value Transformer で指定する名前となる。
//---------- AppController.h ----------
#import <Cocoa/Cocoa.h>


@interface AppController : NSObject {

}

@end
//---------- AppController.m ----------
#import "ColorToRgbTransformer.h"
#import "AppController.h"


@implementation AppController

-(void) applicationDidFinishLaunching:(NSNotification *)notification {
    // autoreleaseされた自作の値変換インスタンスを作って、登録する
    // forName:は、IBのValue Transformerで指定する名前になる
    [NSValueTransformer setValueTransformer:[[[ColorToRgbTransformer alloc] init] autorelease]
                                    forName:@"ColorToRgbTransformer"];
}

@end
  • Interface Builderで、アプリケーションのデリゲートをセットすることも忘れずに。(コントロールキーを押しながらApplicationからApp Controllerに向けてマウスドラッグしてdelegeteを繋げる)

Interface BuilderからColorToRgbTransformerを利用する

  • Interface BuilderのBindingsインスペクタのValue Transformerで、上記forName:で指定した名前 ColorToRgbTransformer をキー入力する。(リストには表示されない。)


変換結果はこんな感じで表示された!