● Carbon視点でiPhone探求(2010/07/23)

  この記事は、MOSAの会員にのみ読むことができるデベロッパー向けの
  ウェブサイトMOSADeN Onlineのに掲載された記事です。ほぼ一ヶ月
  遅れでここに掲載されて行きます。

  〜 環境設定の使い方(その2) 〜


今回は次回の続きです。環境設定ファイルとして確保した配列(NSMutableArray)からパラメータを出し入れする処理を実装します。そして、そのパラメータを利用し、対称画像を登録する時のサウンド発生のON/OFFを管理するようにします。

今回から「しんぶんし」のプロジェクトをiOS 4.0に対応させることにします。そのために利用する開発ツールをXcode 3.2.3に切り替えますのでご了承ください。iOS 4.0対応といっても、4.0特有の機能はまだ何も使いません。今まで通りiOS 3.1.3コンパチブルとしたいので、ビルド設定の「iPhone OS Deployment Target」は、3.1.3と設定しておきます。これにより、iOS 3.1.3のデバイスにも「しんぶんし」をインストールすることが可能です。また、iOS 4.0を搭載したデバイスにインストールすると、何もしなくても高速アプリケーション切り替え機能(メモリ常駐)に対応したことになります。

  

本アプリでは、環境設定のパラメータをCルーチンからアクセスできるようにしてみます。そうする理由は単純で、環境設定のパラメータはあちこちのオブジェクト内で参照されますので、その度に、いちいちメッセージ送り先のPreferencesオブジェクトを得るのが面倒なためです。まず、 Preferences.mで初期化のinitメソッドをオーバライドし、作成したオブジェクトを外部変数のsys_prefへ代入しておきます。これにより、Cルーチン内でこのクラスのインスタンス変数であるdefalutArrayに直接アクセスできるようにります。ただし、この方法はオブジェクトを一つしか作らないクラス(シングルトン・パターンと呼ばれる)にしか適用できませんので御注意ください。

Preferences  *sys_pref;  //  環境設定コントローラ自身

- (id)init
{
if( self=[super init] )
    sys_pref=self;    //  環境設定インスタンス保存
  return self;
}

これで、環境設定に保存されている整数(NSUInteger)パラメータへのインデックス経由の書き込みと読み込み(I/O)は、以下の様なCルーチンで可能となります。

void setPrefInteger( NSUInteger index,NSUInteger value ) // 書き込み
{
  [sys_pref.defalutArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:value]];
}

NSUInteger getPrefInteger( NSUInteger index ) // 読み込み
{
  return [[sys_pref.defalutArray objectAtIndex:index] intValue];
}

このルーチンを使う前に、インスタンス変数のdefalutArray(NSMutableArray)を作成し、先んじてオブジェクト配列へ初期値を代入しておきます。「しんぶんし」では利用しないのですが、例題として、整数だけでなく浮動小数点、日付、文字列を環境設定パラメータとして用意するケースを想定しておきます。整数パラメータは100個用意し、それ以外のパラメータは20個ずつ用意しています。また、整数パラメータの1つ目にはアプリケーションのバージョン番号を、2つ目には対象画像保存時にサウンドを鳴らすかどうかON/OFFのデフォルト値(今回はゼロ...鳴らさない)を代入しておきます。

#define  APP_VERSION 1000 // バージョン番号(1.0.0.0)
#define  MAX_PREF1  100  // 整数パラメータの数
#define  MAX_PREF2  20  // その他のパラメータの数

- (void)initUserDefault // 環境設定の初期化
{
  NSDate    *date;
  NSUInteger  i;
  
  if( defalutArray=[[NSMutableArray alloc] init] )
  {  
    for( i=0;i<MAX_PREF1;i++ ) // 整数 初期化(100個)
      [defalutArray addObject:[NSNumber numberWithInteger:0]];
    for( i=0;i<MAX_PREF2;i++ ); // 浮動小数点 初期化(20個)
      [defalutArray addObject:[NSNumber numberWithDouble:0.0]]
    for( i=0;i<MAX_PREF2;i++ ) // 日付 初期化(1970.01.01)(20個)
    {
      date=[NSDate dateWithTimeIntervalSince1970:0];
      [defalutArray addObject:date];                
    }
    for( i=0;i<MAX_PREF2;i++ ) // 文字列 初期化(ヌル文字列)(20個)
      [defalutArray addObject:@""];
    
    setPrefInteger( 0,APP_VERSION ); // 00番.バージョン番号(1.0.0.0)
    setPrefInteger( 1,0 ); // 01番.画像保存でサウンドを鳴らす(ON/OFF)
  }
}

それから、前回紹介したPreferencesクラスのsaveUserDefaultメソッドですが、アプリケーション終了時だけでなくパラメータ変更時にも呼べるよう、synchronizeメソッドを追加してファイルへの逐次保存を追加しておきます。

- (void)saveUserDefault  //  環境設定の保存
{
  NSUserDefaults  *user;
  
  user=[NSUserDefaults standardUserDefaults];  
  [user setObject:defalutArray forKey:@"UserDefault"]; // 環境設定を保存
  [user synchronize]; // 外部記憶へ書き出し
}

続いて、AboutViewController.hに環境設定パラメータ用のスイッチ(UISwitch)のIBOutlet ab_switchを定義します。そしてInterface BuilderでAboutViewController.xibにスイッチをひとつだけ配置して、それをのab_switchとアクションメソッドのchangeState:へコネクトします。

@interface AboutViewController : UIViewController
{
  IBOutlet  UISwitch  *ab_switch; // 環境設定用のスイッチコントロール
}
@property(nonatomic,assign)UISwitch  *ab_switch;

- (IBAction)changeState:(id)sender // スイッチON/OFF変更のアクションメソッド
{
  SymmetryAppDelegate  *app;
  
  setPrefInteger( 1,ab_switch.on ); // スイッチの状態をパラメータとして保存

  app=[[UIApplication sharedApplication] delegate]; // アプリデリゲーター
  [app.ap_pref saveUserDefault]; // 初期設定のファイル保存
}


  

アバウト表示時にスイッチのON/OFF状態を環境設定パラメータと一致させる必要がありますが、これについては、SymmetryAppDelegate.mに実装したopenAboutViewControllerメソッド(アバウトビューをオープンする)の最後に以下の一行を追加するだけでOKです。

aboutvctr.ab_switch.on=getPrefInteger( 1 ); // 環境設定スイッチのON/OFFセット

最後に対称画像の保存終了時に呼ばれるメソッドの修正です。今までは「画像を保存しました。」と言うメッセージを表示していましたが、今回からは、getPrefInteger( 1 )の内容により、メッセージ表示かサウンドを鳴らすのかを切り替える必要があります。

- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
  NSString   *str,*ok;
  BOOL     sheet=YES;
  UIAlertView  *alertView;
  
  if( ! error ) // 正常に保存
  {
    if( getPrefInteger( 1 ) ) // サウンド発生(ON)
    {
      sheet=NO;  // シートは表示しない
      sendSound();
    }
    else // 保存用アラート表示
      str=NSLocalizedString( @"IMG_SAVED",@"" );
  }
  else // エラー発生 
    str=NSLocalizedString( @"IMG_ERROR",@"" ); // エラー用アラート表示
  if( sheet==YES ) // シートを表示する場合
  {
    ok=NSLocalizedString( @"OK_BUTN",@"" );
    alertView=[[UIAlertView alloc] initWithTitle:str message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:ok,nil];
    [alertView show];
    [alertView release];
  }
}

発生させるサウンドは、お好みのサウンドファイル(send.wav)をResourcesフォルダへ保存して利用します。サウンドを鳴らすルーチンは、以前作成したsysBeep()を少しだけ改良して再利用しています。

AVAudioPlayer *send_beep;

void setupSendSound() // 画像保存用サウンド初期化ルーチン
{
  NSString  *path;
  NSURL   *url;
  
  if( ! send_beep ) // 初期化されていなければファイルを読み込む
  {
    path=[[NSBundle mainBundle] pathForResource:@"send" ofType:@"wav"];
    if( url=[NSURL fileURLWithPath:path] )
      send_beep=[[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
  }
}

void sendSound() // 画像保存用サウンドを鳴らすルーチン
{
  setupSendSound();
  if( send_beep )
  {
    send_beep.currentTime=0; // 再生位置は最初から
    [send_beep play];
  }
}

  

今回で「しんぶんし」について予定していた機能はほぼ実装されました。次回からは、このアプリをiPad用としても動かせるように改良してい行きたいと思います。ユーザインターフェースの大画面への対応や、モデルクラスのCore Dataへの変更などをについて解説できればと考えています。お楽しみに!

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