ユーティリティメソッドを使って書き直す
ソースコード生成時に「アクセサを生成」にチェックを入れておいたので、アクセサメソッドが生成されています。例えばamplitudeのアクセサメソッドはこうなっています。
- (NSNumber *)amplitude
{
NSNumber * tmpValue;
[self willAccessValueForKey:@"amplitude"];
tmpValue = [self primitiveValueForKey:@"amplitude"];
[self didAccessValueForKey:@"amplitude"];
return tmpValue;
}
- (void)setAmplitude:(NSNumber *)value
{
[self willChangeValueForKey:@"amplitude"];
[self setPrimitiveValue:value forKey:@"amplitude"];
[self didChangeValueForKey:@"amplitude"];
}
他のアクセサメソッドもキー文字列が違うだけで、中身はあまり変わりません。たった一つのプロパティに対してこれですから、プロパティの数が増えてくると、いたずらにソースコードの量が増えて見通しが悪くなりそうです。Objective-C 2.0だとこの辺りが解決されているのですが、Tigerもサポートしたいので2.0は使えません。
そこでOscillatorCDのスーパークラスにユーティリティメソッドを用意する事で、この問題を解決する事にします。スーパークラス(親エンティティ)の名前をRMGRootとします。
モデルエディタに戻ってRMGRootエンティティを追加します。属性も関連も追加しませんが「抽象」チェックボックスにはチェックを入れておきます。
そしてOscillatorエンティティの親としてRMGRootを指定します。
先ほど作成したOscillatorCD.hとOscillatorCD.mを削除して、再度新規ファイルを作成します。RMGRootとOscillatorを両方選択しておきます。

//
// RMGRoot.m
//
// Getterを一行で書くためのメソッド
- (id)rmgValueForKey:(NSString *)key
{
id tmpValue;
[self willAccessValueForKey:key];
tmpValue = [self primitiveValueForKey:key];
[self didAccessValueForKey:key];
return tmpValue;
}
インターフェイスファイルにメソッドの宣言を追加します。より簡潔に記載するためのマクロも用意します。VFKはValue For Keyの略です。
//
// RMGRoot.h
// RepeatingMotifGenerator
//
// Copyright 2008 NovemberKou. All rights reserved.
//
#import <CoreData/CoreData.h>
#define VFK(key) [self rmgValueForKey:@key]
@interface RMGRoot : NSManagedObject
{
}
- (id)rmgValueForKey:(NSString *)key;
@end
【失敗例】引数付きマクロの引数と二重引用符
最初はVFKという引数付きマクロは
#define VFK(key) [self rmgValueForKey:@"key"]
と定義していました。ところがビルドして実行してみると、ウィンドウが表示されず何やらうまくいっていない様です。
「実行」メニューの「コンソール」を実行してデバッガコンソールを表示してみると、案の定何やらエラーメッセージが表示されています。keyというキーはないぞと言っている様です。
そこで「ビルド」メニューの「プリプロセス」を実行してみるとVFK(amplitude)が[self rmgValueForKey:@"key"]と展開されている事がわかりました。
そうとわかれば
#define VFK(key) [self rmgValueForKey:@key]
に修正して、使う時はVFK("amplitude")として解決です。引数付きマクロは文字列を扱うので""で囲ってはダメという事でしょうか?
Setter作成をサポートするユーティリティメソッド
次はSetterの方です。これもテンプレートで作成されたメソッドのキー文字列を引数にすればよいのですが、それに加えてアンドゥメニュー項目に現れるアクション名の設定もできる様にします。
- (void)setActionName:(NSString *)actionName
{
if(![UNDO_MANAGER isUndoing] && ![UNDO_MANAGER isRedoing])
[UNDO_MANAGER setActionName:NSLocalizedString(actionName,nil)];
}
// アンドゥのアクション名を同時にセットするSetter
- (void)setValue:(id)value
forKey:(NSString *)key
action:(NSString *)actionName
{
[self willChangeValueForKey:key];
[self setPrimitiveValue:value forKey:key];
[self didChangeValueForKey:key];
if(actionName != nil)
[self setActionName:actionName];
}
ここでUNDO_MANAGERはマクロで定義します。よく使うのでインターフェイスファイルに記述しておきましょう。メソッドの宣言も追加すると、以下の様になります。
//
// RMGRoot.h
// RepeatingMotifGenerator
//
// Copyright 2008 NovemberKou. All rights reserved.
//
#import <CoreData/CoreData.h>
#define VFK(key) [self rmgValueForKey:@key]
#define UNDO_MANAGER [[self managedObjectContext] undoManager]
@interface RMGRoot : NSManagedObject
{
}
- (id)rmgValueForKey:(NSString *)key;
- (void)setValue:(id)value
forKey:(NSString *)key
action:(NSString *)actionName;
@end
Oscillatorのアクセサメソッドを修正する
これで準備が終わりました。OscillatorCDに戻ってアクセサメソッドを修正します。色々と準備したおかげで、以下の様に簡潔に記述できます。
//
// OscillatorCD.m
// RepeatingMotifGenerator
//
// Copyright 2008 NovemberKou. All rights reserved.
//
#import "OscillatorCD.h"
@implementation OscillatorCD
#pragma mark -
#pragma mark Accessor methods
- (NSNumber *)amplitude {return VFK("amplitude");}
- (NSNumber *)frequency {return VFK("frequency");}
- (NSNumber *)phaseLag {return VFK("phaseLag");}
- (NSBezierPath *)waveform {return VFK("waveform");}
- (void)setAmplitude:(NSNumber *)value
{
[self setValue:value forKey:@"amplitude" action:@"setAmplitude"];
}
- (void)setFrequency:(NSNumber *)value
{
[self setValue:value forKey:@"frequency" action:@"setFrequency"];
}
- (void)setPhaseLag:(NSNumber *)value
{
[self setValue:value forKey:@"phaseLag" action:@"setPhaseLag"];
}
- (void)setWaveform:(NSBezierPath *)value
{
[self setValue:value forKey:@"waveform" action:nil];
}
@end
インターフェイスファイルを再生成したので、先ほどUNKNOWN_TYPEをNSBezierPath *に修正した分が消えています。再度修正すると以下の様になります。
親エンティティを指定したのでOscillatorCDクラスのスーパークラスがRMGRootに変わっています。また、そのインターフェイスファイルがインポートされています。
//
// OscillatorCD.h
// RepeatingMotifGenerator
//
// Copyright 2008 NovemberKou. All rights reserved.
//
#import <CoreData/CoreData.h>
#import "RMGRoot.h"
@interface OscillatorCD : RMGRoot
{
}
- (NSNumber *)amplitude;
- (void)setAmplitude:(NSNumber *)value;
- (NSNumber *)frequency;
- (void)setFrequency:(NSNumber *)value;
- (NSNumber *)phaseLag;
- (void)setPhaseLag:(NSNumber *)value;
- (NSBezierPath *)waveform;
- (void)setWaveform:(NSBezierPath *)value;
@end

ホーム
前へ