● Carbon視点でiPhone探求(2009/03/21)

  このニュースは、MOSAの会員にのみ配布されているデベロッパー向けの
  デジタルマガジンMOSADeNのに掲載された記事です。ほぼ一ヶ月遅れで
  ここに掲載されて行きます

 〜 ああ、SysBeep(1)が懐かしい! 〜


今回から、作成したモデルオブジェクトを管理し、アーカイブとしてファイルへ保存やメモリーへの読み込みを行うモデルコントローラの話に入ります。これは、Mac用のCocoaアプリケーションであれば「NSDocument」が行う仕事です。

OOPの世界では、モデル・ビュー・コントローラ(MVC)という単語がよく出てくるのですが、これは大ざっぱなクラス役割分担を指しています。大規模なアプリケーションなどでは、上記コントローラがモデル寄りの役割とビュー寄りの役割に分かれて作業分担している場合があります。片方をモデルコントローラと呼び、もう片方をビューコントローラと呼んだりします。 まあ、正確なクラスカテゴリーの切り分けについては、私も勉強不足で良く理解できていませんが(笑)、例えば、Mac用Cocoaアプリケーションを開発する時に、Xcodeのプロジェクトテンプレート(雛形)から「Cocoa Documentbased Application」を選んで作業を開始すると、必ずAppKitのNSDocumentクラスのお世話になります。

このNSDocumentクラスが、もっとも身近なモデルコントローラの例です。通常このテンプレートを使ったアプリケーションでは、 NSDocumentクラスをスーパークラスとする独自クラスを用意し(例えばMyDocumentクラスとか...)そこで、NSDocumentクラスが実装しているメソッドをオーバライドすることで、ファイル保存されているドキュメントに対する操作(読み込みや書き出し)などを実現します。しかし残念ながら、iPhoneのUIKitには、これに準じるクラスが存在していません。まあ、iPhoneアプリでは不特定多数のファイルを同時に取り扱うケースが少ないので、モデル管理としてはSQLite(データベース用フレームワーク)があれば十分だろうと言う判断かもしれません。

しかし、今回はSQLiteを使わずに、独自でモデルコントローラを実装してみることにします。さてモデルコントローラの話へと移る前に、実際のコーディング作業を効率良く行うための準備をします。まず最初に、テキストエディターの各種設定を自分の環境に合わせることが大事でしょう。それには、Xcode環境設定の「コード入力補助」「キーバインド」「テキスト編集」「フォントとカラー」などに含まれる設定項目の意味を良く理解し、それを自分の環境にマッチした設定に変更する必要があります。まあ、すべてデフォルトでOKな人はまったく問題ないのですが(笑)ちょっとした設定を変更するだけで、ソースコードの入力し易さが激変することがありますので、一度腰を落ち着けてチェックしてみてはいかがでしょうか?

例えば「コード入力補助」の「自動的に候補を表示」の設定ですが、これが機能するのが「大きなお世話」だと感じる人もいるはずです。その場合は「しない」に変更します。候補が表示されるタイミングも「すぐに」と「少し経ってから:」(秒数も指定可能)の2種類から選べますので、どちらが自分のキータッチのタイミングに合うのか試してみることが大事です。加えて、エディター入力時の文字サイズとカラーも環境設定の「フォントとカラー」で調整しておきましょう。大きなスクリーンを利用している人は、10ポイント文字ではさすがに小さすぎますし(老眼ではないとしても)、デフォルトもカラー設定もちょっとビビッド(笑)すぎるような気がします。結局、筆者はすべてのカラーの輝度を落とすことで再調整してしまいました。

そうそう、文字カラー変更の話が出たついでに、このカラー変更の対象となるインスタンス変数名の話もしておきます。前回、モデル (Model )クラスを定義する時に、そのインスタンス変数の先頭を「mo_」という表記で揃えました。これは「二文字+アンダーバーが先頭についているのはインスタンス変数である」という「識別し易さ」を考慮したわけですが、これについては色々な意見があると思います。「カラーを変更すればOKでは?」と言う人もいるでしょう。Apple社のフレームワークで定義されているインスタンス変数は先頭にアンダーバーが付いていますので、それらを継承したクラスの方では一般的な変数名を付けても問題はありません。ですから、「md_name」は、単純に「name」の方が分かり易いという人もいるでしょう。

今までMac用Cocoaアプリケーションを開発する時には、ほとんどの場合はアクセッサを用いてインスタンス変数にアクセスしました。ですから、対象クラスの外でインスタンス変数を記述するようなことは滅多にありませんでした。しかし、プロパティ宣言ができるようになり、ドット演算子によるアクセスが可能となって、インスタンス変数名がソースのあちらこちらに登場するようになりました。この状況で各クラスに同じインスタンス名があると、その名称をエディターで一括変換(全ソース対象)したい場合に問題が生じます。まあ、これはアクセッサメソッド名の一括変換についても同じことが言えるのですが...。とにかく「変数名についてはこうだ!」「メソッド名はこうだ!」と、自分の中で一貫したルールを決めておくことが重要なのかもしれません。

続いてもう一つ! CocoaにはNSLog()という便利なコンソールへのログ書き出しルーチンが存在します。これをうまく活用して何らかの情報を表示すれば、デバッグを効率良く行うことができます。しかし、筆者も含めて昔から簡単なデバッグにビープ音を使っている人も多いと思います(本当か?)。「その処理を通ったのか、通らなかったのか?」「どの処理まで入ってきたのか?」「そこを何回通ったのか?」などなど、ビープ音による識別は、コンソールをオープンせずともちょっとしたチェックが可能で大変便利なのです。 ところが、iPhoneのUIKitにはCarbonのSysBeep(1)やMac版CocoaのNSBeep関数が存在しません。つまり簡単にビープ音を鳴らすことができないのです。

ならばと言うことで、AudioToolboxのAudioServicesCreateSystemSoundID()ルーチンを使い、以下の様なビープ音を鳴らすルーチンを作ってみました。ビープ用のサウンドファイル(bp.wav)をプロジェクトのResourcesグループに登録しておき、アプリから呼び出して使います。

SystemSoundID sys_sound;

void sysBeep()
{
  NSString *path;
  NSURL *url;

  if( ! sys_sound )
  {
    path=[[NSBundle mainBundle] pathForResource:@"bp" ofType:@"wav"];
    if( url=[NSURL fileURLWithPath:path )
      AudioServicesCreateSystemSoundID( (CFURLRef)url,&sys_sound );
  }
  if( sys_sound )
    AudioServicesPlaySystemSound( sys_sound );
}

AudioServicesPlaySystemSound()は短い(5秒以内)サウンドを鳴らすための便利なルーチンです。ところが、現在のiPhoneシミュレーターは、このルーチンでは音がでません(実機は大丈夫)。シミュレーターで鳴らせなくてはデバッグ時には活用できません。Core Audioを使いサウンドを鳴らすクラスを実装すればOKなのですが、処理が少々大げさでビープルーチンとは言い難くなります。困っていたところ、iPhone OS 2.2からAVFoundationと呼ばれるフレームワークが登場し、そこに含まれるAVAudioPlayerクラスを使うと、シミュレーターでも簡単にビープ音が鳴らせることが分かりました。現在では、このルーチンをデバッグにフル活用しています。Objectibve-Cにおいても、こうしたユーティリティ的なルーチンはCルーチンとして実装しておく方が便利です。

AVAudioPlayer  *sys_beep;

void sysBeep()
{
  NSString *path;
  NSURL *url;

  if( ! sys_beep )
  {
    path=[[NSBundle mainBundle] pathForResource:@"bp" ofType:@"wav"];
    if( url=[NSURL fileURLWithPath:path] )
      sys_beep=[[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
  }
  if( sys_beep )
  {
    sys_beep.currentTime=0;
    [sys_beep play];
  }
}

ちょっと寄り道をしましたが、次回から本格的にモデルコントローラクラスを実装していきたいと思います。まずは、モデルのアーカイブ化を行うために、NSCodingプロトコルに準拠したencodeWithCoder:とinitWithCoder:の2つのメソッドを用意することから始めたいと思います。

copyright 2009 Ottimo, Inc. All rights reserved
無断転載・引用禁止