モデルクラスをカット&ペーストに対応させる【実践的Macintoshプログラミング解説】

印刷用表示 |テキストサイズ 小 |中 |大 |

CoreData版 Repeating Motif Generator の開発 Repeating Motif Wonderland CoreData 実践的 Macintosh プログラミング解説

LinkIconホーム

更新日 2009-05-24

原図をカット&ペーストできる様にする

モデルクラスをカット&ペーストに対応させる

 カット&ペーストに対応するためにモデルクラスが実行すべき事はdataType, copyKeys, stringDescription, dictionaryRepresentationなど必要なメソッドをオーバーライドする事です。

 OscillatorCD, MixerCD, MasterMotifCDの各クラスを対応させていきます。

OscillatorCDの対応

 OscillatorCDは本質的には第三のプロジェクトと変わらないのですが、stringDescriptionを少し変更したのでリストを掲載しておきます。説明用の文字列を削除し、数値のみ出力する様に変更しました。

//
//  OscillatorCD.m
//

#pragma mark -
#pragma mark PasteBoard methods

+ (NSArray *)copyKeys
{
    static NSArray *oscillatorCopyKeys = nil;

    if(oscillatorCopyKeys == nil)
        oscillatorCopyKeys = [[NSArray alloc] initWithObjects:@"amplitude", @"frequency", @"phaseLag", nil];

    return  oscillatorCopyKeys;
}

- (NSString *)stringDescription
{
    return  [NSString stringWithFormat:@"%3d, %2d, %3d",
             [[self amplitude] intValue],[[self frequency] intValue],[[self phaseLag] intValue]];
}

MixerCDの対応

 MixerCDはOscillatorCDを所有するのでcopyKeysとstringDescriptionをオーバーライドしただけでは不十分で、dictionaryRepresentaionもオーバーライドする必要があります。この辺りの説明はLissajousで行ないましたので、そちらを見て下さい。

 一方、Mixerは単独でカット&ペーストの対象にはならないのでdataTypeを実装する必要はありません。

 Mixerエンティティは属性を持たず、関連しか持っていません。したがってcopyKeysはnilを返します。copyKeysがnilだとスーパークラスのdictionaryRepresentationがうまく動作しないので、dictionaryRepresentationメソッドではスーパークラスのメソッドを呼びださずに新しく可変辞書を作成しています。

 したがってMixerCDのカット&ペーストに対応するコードは以下の様になります。

//
//  MixerCD.m
//

#pragma mark -
#pragma mark PasteBoard methods

+ (NSArray *)copyKeys
{
    return  nil;
}

- (NSString *)stringDescription
{
    return  [NSString stringWithFormat:@"%@, %@, %@",
             [[self osc1] stringDescription],[[self osc2] stringDescription],[[self osc3] stringDescription]];
}

- (NSDictionary *)dictionaryRepresentation
{
    NSMutableDictionary *dictionary;

    dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
    [dictionary setObject:[[self osc1] dictionaryRepresentation] forKey:@"oscillator1"];
    [dictionary setObject:[[self osc2] dictionaryRepresentation] forKey:@"oscillator2"];
    [dictionary setObject:[[self osc3] dictionaryRepresentation] forKey:@"oscillator3"];

    return  dictionary;
}

- (NSDictionary *)oscillator1   {return  nil;}
- (NSDictionary *)oscillator2   {return  nil;}
- (NSDictionary *)oscillator3   {return  nil;}

- (void)setOscillator1:(NSDictionary *)dictionary   {[[self osc1] setValuesForKeysWithDictionary:dictionary];}
- (void)setOscillator2:(NSDictionary *)dictionary   {[[self osc2] setValuesForKeysWithDictionary:dictionary];}
- (void)setOscillator3:(NSDictionary *)dictionary   {[[self osc3] setValuesForKeysWithDictionary:dictionary];}

MasterMotifCDの対応

 MasterMotifCDはMixerCDを所有するのでcopyKeys, stringDescriptionに加えてdictionaryRepresentationもオーバーライドします。また単独でカット&ペーストの対象になるのでdataTypeもオーバーライドします。

//
//  MasterMotifCD.m
//

#pragma mark -
#pragma mark PasteBoard methods

+ (NSString *)dataType      {return  @"RMGMasterMotifPBoardType";}

+ (NSArray *)copyKeys
{
    static NSArray *masterMotifCopyKeys = nil;

    if(masterMotifCopyKeys == nil)
        masterMotifCopyKeys = [[NSArray alloc] initWithObjects:@"resolution", @"order", nil];

    return  masterMotifCopyKeys;
}

- (NSString *)stringDescription
{
    return  [NSString stringWithFormat:@"%3d, %@, %@",
             [[self resolution] intValue],[[self x] stringDescription],[[self y] stringDescription]];
}

- (NSDictionary *)dictionaryRepresentation
{
    NSMutableDictionary *dictionary;

    dictionary = [[[super dictionaryRepresentation] mutableCopy] autorelease];
    [dictionary setObject:[[self x] dictionaryRepresentation] forKey:@"xmixer"];
    [dictionary setObject:[[self y] dictionaryRepresentation] forKey:@"ymixer"];

    return  dictionary;
}

- (NSDictionary *)xmixer    {return nil;}
- (NSDictionary *)ymixer    {return nil;}

- (void)setXmixer:(NSDictionary *)dictionary    {[[self x] setValuesForKeysWithDictionary:dictionary];}
- (void)setYmixer:(NSDictionary *)dictionary    {[[self y] setValuesForKeysWithDictionary:dictionary];}

原図の辞書表現の実例

synthesizeMotif.png 右の原図のdictionaryRepresentationで得られる辞書をNSLog()で見てみると、以下の様になりました。辞書の構造が感覚的につかめるのではないかと思います。

{
    order = 0;
    resolution = 200;
    xmixer =     {
        oscillator1 =         {
            amplitude = 100;
            frequency = 1;
            phaseLag = 0;
        };
        oscillator2 =         {
            amplitude = 25;
            frequency = 4;
            phaseLag = 224;
        };
        oscillator3 =         {
            amplitude = 10;
            frequency = 7;
            phaseLag = 290;
        };
    };
    ymixer =     {
        oscillator1 =         {
            amplitude = 100;
            frequency = 1;
            phaseLag = 60;
        };
        oscillator2 =         {
            amplitude = 25;
            frequency = 4;
            phaseLag = 43;
        };
        oscillator3 =         {
            amplitude = 10;
            frequency = 3;
            phaseLag = 0;
        };
    };
}

原図の文字列表現の例

 15個の原図を選択してコピーし、テキストエディタにペーストすると以下の様になります。先頭行が上の原図に対応する文字列です。

200, 100,  1,   0,  25,  4, 224,  10,  7, 290, 100,  1,  60,  25,  4,  43,  10,  3,   0
200,  27,  1, 344,  48,  4,  91,  81,  2, 349,  31,  5, 119,  86,  2,  44,  92,  1,  95
200, 100,  2,   0,  50,  7,  90,  25, 16, 180, 100,  1,   0,  50,  8,  90,  25, 17, 180
200,  50,  1,   0, 100,  2,  90,  40,  5,   0, 100,  1,  90,  30,  3,  90,   0,  1,   0
200, 100,  1,   0,  40,  2, 180,  75,  3,  90,  50,  1,  90,  20,  2,  90,  40,  3,  90
200,  74,  1,   0,  10,  2,  90,  11, 17, 180,   5,  1,  90,  31,  3, 180,  25,  7, 270
200, 100,  1,   0,  50,  3,  20,   0,  1,   0, 100,  2,  90,  50,  4, 110,   0,  1,   0
200, 100,  1,   0,  50,  2,   0,   0,  1,   0, 100,  1, 270,  50,  2,  90,   0,  1,   0
200,  56,  5, 298,  39,  3, 117,  73,  7, 354,  34,  9,  48,  41,  1, 281,  78,  3,  41
200,  14,  2, 105,  87,  3, 168,  13,  5, 347,  30,  2,   5,  61,  4, 319,   2,  2, 341
200, 100,  1,   0,  50,  2, 180,  50,  4,   0,  25,  1,  90,  40,  2, 270,  30,  4,  90
200, 100,  1,   0,  25,  2,   0,  50,  3,   0, 100,  1,  90,  25,  2,  90,  50,  3,  90
200,   8,  3, 269,  47,  9, 289,  51,  7, 214,  55,  2, 333,  98,  2, 122,  54,  2,  76
200,   8,  1,  76,   3,  3, 115,  74,  1, 335,  90,  1, 184,  75,  3, 117,  53,  5, 348
200,  26,  5,  76,   3,  3, 115,  74,  1, 335,  90,  1, 184,  75,  3, 117,  53,  5, 348