Cocoa Break Logo Top Soft Develop  脱力空間 Logo
Apple Web Badge
made by mi

概要 翻訳 ソース リンク がらくた

概要 Examples ADC Samples 3rd Parties etc CBOriginals

Preferences

以下は、Mac OS X 10.4.11 上の Xcode 2.5 で説明しています。

目次:
1 実行
2 ファイル構成
3 PreferencesExample.c
3.1 main 関数
3.2 show 関数 関数
3.3 simplePreferencesExample 関数
4 まとめ

1 実行

まず、Xcode 上でビルドして実行してみます。Xcode の実行ログは以下のようになります。

There is no old high score. Recording new high score, 5

翻訳すると、次のようなメッセージが出力されています。

古いハイスコアはありません。 新しいハイスコア 5 を記録。

さて、もう一度実行してみます。すると今度は次のようなメッセージが出ます。

The old high score was 5. Recording new high score, 10
古いハイスコアは 5 でした。 新しいハイスコア 10 を記録。

このサンプルは、環境設定に格納したハイスコアの数値をとりだし、毎回 5 ずつ増やしていることがわかります。ここで、現在のユーザーフォルダ内の「ライブラリ」>「Preferences」を見てみましょう。「A Game.plist」という名前のファイルがあります。プロパティリストエディタで開くと、「High Score」というキーと、数値 10 が格納されているのがわかります。

2 ファイル構成

プロジェクトを構成しているファイルは、PreferencesExample.c だけです。あとは External Frameworks and Libraries 内で Core Foundation フレームワークに対してリンクされていることに注意してください。

3 PreferencesExample.c

3.1 main 関数

まず、main 関数を見てみます。PreferencesExample.c では以下のようになっています。

StringExample.c > main
int main (int argc, const char *argv[]) { simplePreferencesExample(); return 0; }

コマンド行からの引数は一切利用せず、引数なしの 1つの関数を呼び出しているだけです。これらの関数を見ていきます。

3.2 show 関数

その前に、サンプルでログ出力をするため、共通に定義されている関数があります。それは show です。この関数は、CFString オブジェクトである書式文字列と、可変個の書式変数の値を渡すことで、結果を printf で出力してくれます。

PreferencesExample.c > show()
void show(CFStringRef formatString, ...) { CFStringRef resultString; CFDataRef data; va_list argList; va_start(argList, formatString); // 可変個引数受けとり用リスト作成 resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList); // リストを使って CFString を作成 va_end(argList); // 可変個引数受けとり用リスト解放 data = CFStringCreateExternalRepresentation (NULL, resultString, CFStringGetSystemEncoding(), '?'); // 出力用のシステムエンコーディング文字データ作成 if (data != NULL) { printf ("%.*s\n\n", (int)CFDataGetLength(data), CFDataGetBytePtr(data)); // 標準出力 CFRelease(data); // データ解放 } CFRelease(resultString); // 変換後文字列を解放 }

まず、可変個引数の受けとり用のリストを作成します。ここでは行っていませんが、このリストから type va_arg(va_list ap, type); で引数をとりだすことができます。type とあるように、あらかじめ型がわかっている必要があります。このリストを使って、CFStringCreateWithFormatAndArguments 関数で、resultString に結果の文字列を作成しています。この関数の引数は、最初がアロケーター(NULL はデフォルト)、次は書式指定のオプション(現在は無効なのでつねに NULL)、その次が書式文字列の CFString で、最後が va_list 型になっています。アロケーターがデフォルトになっていることに注意してください。これにより、この割り当ては、サンプルのアロケーターを経由しません。

次に、CFStringCreateExternalRepresentationprintf に渡すための文字列データが入れられた CFData を作っています。最後の '?' は変換できない文字をどういう文字として表すかを指定するものです。このデータ作成が成功したら、次に printf に渡します。「%.*s\n\n」という書式文字列で、%s はヌル終端の文字列を渡すことを指定し、その前の精度指定「.*」は、最大文字数を表し、ここでは * で引数として渡すことを指定しています。そのため、文字列後の引数は、データのバイト長、データという順番で渡されています。あとは割り当てたデータを解放しています。

この関数に渡す書式文字列は、たいてい CFSTR マクロでコード中に直接書かれます。このマクロは、定数文字列から CFString を作ります。ただし、7 ビット ASCII(127 までのコード)しかサポートしてないことに注意してください。日本語を使うなら、別の方法が必要です。

3.3 simplePreferencesExample 関数

simplePreferencesExample は、以下のようになっています。この関数は、『Core Foundation のための環境設定プログラミングトピック』>「単純な環境設定の更新」で紹介されているコード例とほとんど同じです。コメント量などが違うので、訳して、説明も追加します。

AllocatorExample.c > simplePreferencesExample
CFStringRef appName = CFSTR("A Game"); // アプリケーション ID CFStringRef highScoreKey = CFSTR("High Score"); // 環境設定のキー CFNumberRef value; int highScore; // 最初に以前の値を取得する... // CFPreferencesCopyAppValue() と CFPreferencesSetAppValue() は、 // ユーザーごと、アプリごとの環境設定を読み書きするアプリにとって最も単純な方法 // これらはすべてのマシン上(もちろん、このユーザーがログインできるもの、 // マシンにローカルなユーザーに対して、環境設定は最終的にはホストによって制限されることになる) // これらの関数は、さまざまな場合における検索も行う。 // 環境設定がより特定でないドメイン(たとえば、「すべてのアプリに対して」)で設定されていたら、 // その値はこの呼び出しで取得されることになる。 // これは何らかの環境設定値のグローバルな設定を可能にする // (これは誰かの設定を他の人のものより意味をもつものにする) // 環境設定内の任意の「プロパティリスト」型を読み書きできることに注意 // これらは CFArray、CFDictionary、CFNumber、CFBoolean、CFData、CFString。 // このサンプルでは、CFNumber だけを示す。 value = CFPreferencesCopyAppValue(highScoreKey, appName); //1 if (value) { // 数値は、CFNumber として環境設定から出てくる if (!CFNumberGetValue(value, kCFNumberIntType, &highScore)) highScore = 0; //2 CFRelease(value); show(CFSTR("The old high score was %d."), highScore); } else { // 以前の値がない show(CFSTR("There is no old high score.")); highScore = 0; } highScore += 5; //3 show(CFSTR("Recording new high score, %d"), highScore); value = CFNumberCreate(NULL, kCFNumberIntType, &highScore); CFPreferencesSetAppValue(highScoreKey, value, appName); CFRelease(value); // 明示的な同期なしでは、保存された値は実際には書き出されない。 // 複数の環境設定を書いているなら、最後のものの後にだけ同期したいかもしれない。 // 環境設定パネルは、ユーザーが「OK」をクリックしたとき、同期させたいかもしれない。 // 場合によっては、アプリが終了するまで同期したくないかもしれない。 // AppKit は、アプリ終了時に自動的に同期する。 // そのため Cocoa アプリはこれを行う必要はない。 (void)CFPreferencesAppSynchronize(appName); //4 }

構造自体は非常に簡単なのでわかりやすいと思います。まず最初に以前の値を、1 で、CFPreferencesCopyAppValue で取得しています。ここで引数は、キーの名前の CFString オブジェクト、そしてアプリケーション ID です。highScoreKeyappName は関数の先頭にあります。

このサンプルでは、appName として定数文字列を設定していますが、通常は、kCFPreferencesCurrentApplication 定数を渡せば、現在のアプリケーションに対する環境設定になります。それに変えてビルドしてみます。古いハイスコアがないことを示すメッセージが出たことでしょう。環境設定フォルダ内を見てみると、「A Game.plist」とは別に「PreferencesExample.plist」というファイルができているのがわかります。バンドル形式の info.plist をもつアプリケーションでは、通常、アプリケーションの識別子が使われます。このサンプルのようなツール類に対しては、コマンド名がそのまま使われていることがわかります。定数には、もっと他の設定もあります。ただし、この引数に NULLkCFPreferencesAnyApplication(すべてのアプリケーション共通)を渡すことはできません。また、この部分に他のアプリケーションの環境設定ファイル名(通常は識別子だが、場合によっては違うだろう)を指定することで、別アプリケーションから他のアプリケーションの環境設定ファイルを変更することができます。これはアプリケーションの表面に出ない設定を修正したりするツールで使える手法です。

つぎに戻り値 valueNULL でないかチェックしています。CFPreferencesCopyAppValue 関数は、値が見つからなかった場合、NULL を返します。

値が見つかったら、2 で、CFNumber の関数を使って、その値を int に変換しています。この関数は、失敗したら false を返すので、その場合 highScore は 0 となります。それから値オブジェクトを解放し、highScore にコピーした int 値をメッセージとともに表示しています。値が返らなければ、以前の値がないというメッセージを表示し、0 を代入しています。

値があれば、変換はほぼ失敗することがないように思われるので、ここでのチェックは心配しすぎと思うかもしれません。しかし、上で書いたように、別アプリから環境設定値が変えられる可能性があります。もしかしたら、このアプリの実装を知らないツールが、勝手に文字列や他のオブジェクトをこれに設定しているかもしれません。そのため、値が適切かどうかを常にチェックしたほうがいいでしょう。

つぎに、3 で、値に 5 を加えて、それを記録することを告げるメッセージを表示し、保存用の CFNumber オブジェクトを作っています。もちろん、取得したものを修正して保存するのも可能ですが、ここではサンプルなので、アプリケーション等で通常行う手順として、まず初期化して、それからさまざまな操作を行い、最後に変更した設定を保存するときのように、別の CFNumber オブジェクトを扱っています。それから、CFPreferencesSetAppValue 関数で保存しています。引数は値が増えただけです。

最後に 4 で、環境設定の同期を行っています。これにより値が書き出されます。デバッガ等を使って停止しながら見てみれば、この時点で書き出しが行われていることを確認できるでしょう。

4 まとめ

サンプル自体かなり簡単で、環境設定の扱いも簡単であることがわかると思います。軽く触れましたが、どういう単位で環境設定を保存するのか(ドメイン-複数アプリケーションをスイートとしてグループ化できる機能もある)など、通常と違う形で使用するときは、リファレンスやガイドを参照する必要があります。


管理人:神吉 秀典 E-mail:puer@ba.wakwak.com