今回は、「しんぶんし 3」でImageFileクラスとして定義したモデルクラス(メインデータ構造の定義)を、iPhone用アプリケーションの「Symmetry」へと移植する作業を行いたいと思います。
モデルクラスの話へ入る前に、前回積み残した話題をひとつだけお話します。iPhoneアプリケーションのローカライズですが、日本で開発したものであっても、少なくとも「英語」だけには対応しておきたいところです(Symmetryはそうする予定)。当然、日本語環境でしか意味を持たないアプリ(そんなに多くはない)つまり日本でしか販売を考えていないものなら日本語のみでOKですが、ワールドワイドでの販売を考えている場合には、英語ローカラーズに対応しておけば、それ以外の国での販売にもそこそこ対応できます。当然、フランス語、スペイン語、イタリア語、ドイツ語、ポルトガル語、 ロシア語程度がローカライズできれば、間違いなく販売数増加に貢献するでしょう。
もし、外国人の友達がいれば、そうした人達にちょっとローカライズ作業を手伝ってもらうのが良策ですね(笑)。翻訳が正しいかどうか分からない状況下では、自動翻訳ソフトや無料Webサービスを使うのはやめた方が良いでしょう。みっともない翻訳を掲載すれば、そのアプリケーションの評判まで落としかねません。例えば、アプリケーションの内容解説やユーザインターフェース回りの簡単な文字列については、有料(わりと低価格)で翻訳サービスを提供しているサイトが幾つかあるようです。筆者は利用したことがないのですが、そうした翻訳サービスをうまく活用することもアリでしょう。ちなみに、以前に「 DYS: Translations」というサイトを利用している方の話を聞いたことがあります。
http://www.dystranslations.com/
さて「しんぶんし3」でのモデルクラス ですが、 ImageFileという名称で、以下の様に定義(ImageFile.h)していました。このクラスのインスタンス(メンバー)変数は、すべてプロパティ宣言されています。
#import <Quartz/Quartz.h>
#import <Cocoa/Cocoa.h>
@interface ImageFile : NSObject <NSCoding>
{
NSString *path;
NSString *type;
CGRect srt;
unsigned int flag;
int kind;
int para;
}
@property(retain)NSString *path;
@property(retain)NSString *type;
@property(assign)CGRect srt;
@property(assign)unsigned int flag;
@property(assign)int kind;
@property(assign)int para;
@end
実際の実装( ImageFile.m)では、各プロパティは@synthesizeディレクティブで宣言しておきます。これにより、プロパティのgetterメソッドとsetterメソッドを用意する必要がなくなります(コンパイラが適切に用意してくれる)。ちなみに、readonlyプロパティの場合はgetterメソッドのみが用意されます。
#import "ImageFile.h"
@implementation ImageFile
@synthesize path,type,srt,flag,kind,para;
// ここに必要なメソッドを実装する!
@end
#importの内容などを書き替えれば、このままの状態でiPhone用ソースコードとして利用してもほとんど問題ありませんが、先を見越してiPhone用に少しだけ改造しておきます。クラス名は分かり易くModelと変えます。よってクラス定義ファイルはModel.hとなります。まずは#import ですが、<Quartz/Quartz.h>は不必要となり<UIKit/UIKit.h>だけでOKです。Mac用Cocoaアプリケーションでは、CGRect構造体がQuartz.hに定義されているためにimportが必要でしたが、iPhone用アプリで使うUIKitでは、CoreGraphicsフレームワークが常用されるので、特別呼び込む必要がないわけです。また、NSUIntegerはunsigned int、NSIntegerはintと定義されています(現状)。
#import <UIKit/UIKit.h>
@interface Model : NSObject <NSCoding>
{
NSString *md_name;
NSString *md_type;
UIImage *md_image;
CGRect md_rt;
NSUInteger md_flag;
NSInteger md_kind;
NSInteger md_para;
}
@property(nonatomic,retain)NSString *md_name;
@property(nonatomic,retain)NSString *md_type;
@property(nonatomic,retain)UIImage *md_image;
@property(nonatomic,assign)CGRect md_rt;
@property(nonatomic,assign)NSUInteger md_flag;
@property(nonatomic,assign)NSInteger md_para;
@property(nonatomic,assign)NSInteger md_kind;
- (id)initWithName:(NSString *)name type:(NSString *)type;
@end
プロパティの属性としてnonatomicが宣言されていますが、これはプロパティへのアクセスに対してマルチスレッド環境を想定していないことを意味しています。その代わりに高速なアクセスが約束されます。将来的には、幾つかのプロパティについて nonatomic宣言を外すかもしれませんが、現状はこの状態としておきます。以下が、実際のクラス実装となるModel.mです。とりあえず、初期化メソッドとしてinitWithName:type:をひとつだけ用意してみました(そのまま使うかどうかは?です)。 NSCodingプロトコルに準拠した、encodeWithCoder:とinitWithCoder:の2つのメソッドについては、モデルのアーカイブ化を行う時に実際に実装したいと思います。
#import "Model.h"
@implementation Model
@synthesize md_name,md_type,md_image;
@synthesize md_rt,md_flag,md_kind,md_para;
- (id)initWithName:(NSString *)name type:(NSString *)type
{
if( self=[super init] )
{
self.md_name=name;
self.md_type=type;
}
return self;
}
- (void)dealloc
{
[md_name release];
[md_type release];
[md_image release];
[super dealloc];
}
- (void)encodeWithCoder:(NSCoder *)coder // アーカイブ・エンコード用
{
// 後ほど実装する
}
- (id)initWithCoder:(NSCoder *)coder // アーカイブ・デコード用
{
if( self=[super init] )
{
// 後ほど実装する
}
return self;
}
@end
Model.mで注目すべき記述は以下の箇所です。
self.md_name=name;
self.md_type=type;
ドット演算子を使って代入していますので、値の代入時にプロパティの属性で定義したretainをsetterメソッドが実行します。 これを、md_name=name;と記述すると(記述は可能)md_nameに対してretainは行われず、メッセージ(引数)として渡されたnameがreleaseされると同時に、モデルオブジェクトに蓄えたmd_nameもメモリーから解放されてしまいます。くれぐれも御注意ください。
次回は、作成したモデルオブジェクトを管理し、アーカイブとしてファイルへ保存やメモリーへの読み込みを行うモデルコントローラを用意してみます。これは、Mac用のCocoaアプリケーションであれば「NSDocument」が行う仕事と同じです。