2012年6月アーカイブ

こんにちは。開発担当のICTFです。

今回はアプリの環境設定を普通のクラスプロパティのように扱えながら、且つアプリを終了しても保持し続けることができるクラス(以下AppSettingクラス)を設計していきます。

このクラスの仕様は以下の通りです。
1. AppSettingはシングルトンとする。
2. AppSettingは各環境設定値にアクセスする為のプロパティを持つ
3. 環境設定値の値が変わった場合、AppSetting内部でUserDefaultに保存する
4. 各環境設定値のデフォルト値をUserDefaults.plistに定義し、AppSetting内でUserDefaultに初期値として設定する
5. AppSetting初期化時にUserDefaultから各設定値を呼び出し、各プロパティに設定する

[AppSetting.h]

// ユーザデフォルトに格納される値のキー

#define APP_SETTING_KEY_SOUND_EFFECT @"AppSettingKeySoundEffect"

#define APP_SETTING_KEY_SOUND_EFFECT_VOLUME @"AppSettingKeySoundEffectVolume"

#define APP_SETTING_KEY_SOUND_DECISION @"AppSettingKeySoundDecision"

#define APP_SETTING_KEY_SOUND_CANCEL @"AppSettingKeySoundCancel"


// アプリのセッティングに関するクラス

@interface AppSetting : NSObject

{

    BOOL         _isPlaySoundEffect;    // 効果音を再生するか

    float        _soundEffectVolume; // 効果音のボリューム

    NSString*    _decisionSoundFileName;// 決定音ファイル名

       NSString*    _cancelSoundFileName; // キャンセル音ファイル名

}


@property (nonatomic, readwriteBOOL isPlaySoundEffect;

@property (nonatomic, readwritefloat SoundEffectVolume;

@property (nonatomic, retain, readwriteNSString* DecisionSoundFileName;

@property (nonatomic, retain, readwriteNSString* CancelSoundFileName;


// このクラスのインスタンスを得る

+(AppSetting*)sharedAppSetting;


// このクラスのインスタンスを破棄する

+(void)deleteInstance;


@end


サンプルでは、音に関する4つの項目をプロパティとして追加しました。
各設定値ごとに1つずつ#defineで文字列を定義します。
この文字列はUserDefaultへのアクセス時にキーとして用います。
また、必要であれば設定値が変更されたことを通知する際のキーとしても使用できます。

シングルトンとして運用しますので、AppSettingのインスタンスを得るメソッド、インスタンスを破棄するメソッドを追加します。

AppSetting.mの実装に入る前にUserDefaults.plistを実装しましょう。
UserDefaults.plistをプロジェクトに新規追加して下さい。
UserDefaults.plistの中身は、以下の様になります。
・KeyはAppSetting.hで定義した4つの文字列
・Typeは各プロパティに該当する型
・Valueは初期値として設定したい値
スクリーンショット 2012-06-14 11.07.44.png
次にAppSetting.mの実装に入ります。
[AppSetting.m]

@implementation AppSetting


// 自身のインスタンスを静的変数に保持する

static AppSetting *_AppSettingInstance = nil;


// 自身のインスタンスを削除できるかを指すフラグ

bool _canAppSettingDelete = NO;


// このクラスのインスタンスを得る

+(AppSetting*)sharedAppSetting

{

@synchronized(self) {

        if (!_AppSettingInstance) {

            _AppSettingInstance = [[self alloc] init];

        }

    }

    return _AppSettingInstance;

}


// このクラスのインスタンスを破棄する

+(void)deleteInstance

{

if (_AppSettingInstance) {

        @synchronized(_AppSettingInstance) {

            _canAppSettingDelete = YES;

            [_AppSettingInstance release];

            _AppSettingInstance = nil;

            _canAppSettingDelete = NO;

        }

    }

}


@dynamic isPlaySoundEffect;

-(BOOL) isPlaySoundEffect

{

return _isPlaySoundEffect;

}

-(void) setIsPlaySoundEffect:(BOOL)isPlaySoundEffect

{

if (_isPlaySoundEffect == isPlaySoundEffect) {

return;

}

_isPlaySoundEffect = isPlaySoundEffect;

// ユーザデフォルトに書き込む

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

[defaults setBool:_isPlaySoundEffect forKey:APP_SETTING_KEY_SOUND_EFFECT];

[defaults synchronize];

}


@dynamic SoundEffectVolume;

-(float) SoundEffectVolume

{

return _soundEffectVolume;

}

-(void) setSoundEffectVolume:(float)SoundEffectVolume

{

if (_soundEffectVolume == SoundEffectVolume) {

return;

}

_soundEffectVolume = SoundEffectVolume;

// ユーザデフォルトに書き込む

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

[defaults setFloat:_soundEffectVolume forKey:APP_SETTING_KEY_SOUND_EFFECT_VOLUME];

[defaults synchronize];

}


@dynamic DecisionSoundFileName;

-(NSString*) DecisionSoundFileName

{

return _decisionSoundFileName;

}

-(void) setDecisionSoundFileName:(NSString *)DecisionSoundFileName

{

if ([_decisionSoundFileName isEqualToString:DecisionSoundFileName]) {

return;

}

[_decisionSoundFileName release];

_decisionSoundFileName = [DecisionSoundFileName retain];

// ユーザデフォルトに書き込む

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

[defaults setObject:_decisionSoundFileName forKey:APP_SETTING_KEY_SOUND_DECISION];

[defaults synchronize];

}


@dynamic CancelSoundFileName;

-(NSString*) CancelSoundFileName

{

return _cancelSoundFileName;

}

-(void) setCancelSoundFileName:(NSString *)CancelSoundFileName

{

if ([_cancelSoundFileName isEqualToString:CancelSoundFileName]) {

return;

}

[_cancelSoundFileName release];

_cancelSoundFileName = [CancelSoundFileName retain];

// ユーザデフォルトに書き込む

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

[defaults setObject:_cancelSoundFileName forKey:APP_SETTING_KEY_SOUND_CANCEL];

[defaults synchronize];

}


// ------------------------------------


-(id) init

{

if (self == [super init]) {

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

// デフォルト値を設定ファイルから読み込み、設定する

NSString* userDefaultsValuesPath;

NSDictionary* userDefaultsValuesDict;

userDefaultsValuesPath = [[NSBundle mainBundle] pathForResource:@"UserDefaults" ofType:@"plist"];

userDefaultsValuesDict = [NSDictionary dictionaryWithContentsOfFile:userDefaultsValuesPath];

[defaults registerDefaults:userDefaultsValuesDict];


// 設定情報をユーザデフォルトから読み込む

_isPlaySoundEffect = [defaults boolForKey:APP_SETTING_KEY_SOUND_EFFECT];

_soundEffectVolume = [defaults floatForKey:APP_SETTING_KEY_SOUND_EFFECT_VOLUME];

_decisionSoundFileName = [[defaults objectForKey:APP_SETTING_KEY_SOUND_DECISION] retain];

_cancelSoundFileName = [[defaults objectForKey:APP_SETTING_KEY_SOUND_CANCEL] retain];

}

return self;

}


-(void) dealloc

{

[super dealloc];

}


少し長いですが、やっていることは単純です。
順番に見て行きましょう。
まずシングルトンとして運用する為に、自己インスタンスを保持する静的変数_AppSettingInstanceを定義しています。
_canAppSettingDeleteは安全に自己インスタンスを破棄する為のフラグです。
sharedAppSettingメソッドでは、静的変数に自己インスタンスを設定して返します。
deleteInstanceメソッドでは静的変数に保持している自己インスタンスを解放しています。
この記事では載せませんが、AppDelegateのdeallocなどで忘れずにAppSettingのdeleteInstanceメソッドをコールして下さい。

次にこのクラスの肝とも言えるプロパティの挙動を記述します。
単に@synthesizeするだけでは用件を満たせませんので、@dynamicで定義します。
プロパティの値を返すメソッドはそのまま該当するメンバ変数の値を返します。
プロパティの値を設定するメソッドでは、該当するメンバ変数に値を設定した後、UserDefaultに値を保存しています。
UserDefaultに値を保存する際のキーとして.hで定義した値を使用します。

initメソッドでは、AppSettingの初期化処理として前回設定された値の読み込み、あるいは初めてアプリが起動された際のデフォルト値の設定を行なっています。

以上でAppSettingクラスの実装は終了です。
アプリの設定値を呼び出したい場合は、次の様に記述します。
[AppSetting sharedAppSetting].プロパティ
アプリの設定値を変更したい場合は、次の様に記述します。
[AppSetting sharedAppSetting].プロパティ = x;
値の保持に関する処理はカプセル化されていますので、気にする必要はありません。

あとはボリュームの変更など設定値が変わった際、即時動作を変えたい場合などに.hで定義した文字列をキーとした通知を発行するのもなかなか便利かもしれません。
こんにちは。開発担当のICTFです。

本日電卓アプリである「Mono Calculator」が発売開始となりました!
Icon@2x.png
Mono Calculatorは、Mono(モノ)という数値の入れ物を使って公式を作成し、その公式をコピーしながら必要な値のみを変える方式を採用した新しいタイプの電卓アプリです。

計算の共通項が多く且つ計算の回数が多いほど、通常の電卓と比べて必要な操作が少なくなります。
一度作った公式は電卓が記録しますので、使うほどに賢くなっていきます。

公式サイト:
http://ict-fractal.com/ICTF0013/index.html

無料で使えるLite版も同時リリースしておりますので、是非一度お試しください!