Shared User Defaults

ここでは、バインディングを使って簡単に環境設定の値を保存する方法についてメモする。

環境設定用のパネルもしくはウィンドウを作って、そこで一括していろいろな値を管理するのがいいけど、まあ、どこの値でも問題なくできるはず。今のところわかっているのは、基本的な使い方だけなので、ここで扱うのは、ほんとに基本だけ。もっといろいろわかったら、後で足していく。

ここでは、Preferences という名前のウィンドウを作っている。

Text Field

Text Field からやってみる。Text Field を選択して、Inspector で Bindings を選ぶ。Values の横の三角をクリックして開ける。

ここで、Bind to: で、Shared User Defaults Controller を選ぶ。

選んだら、Bind to: にチェックを入れる。

次に、保存するときの目印にする値を Model Key Path に入れる。他の特別さえできれば何でもいい。ただ、自分でもわからないような前を付けると、何かあったときに面倒なので、一目見てわかる名前にするのがいい。ここでは、Text Field は一つしかないので、textField とした。もうひとつ、Text Field の時にしておくことは、Continuously Updates Values にチェックを入れる。これにチェックが入ってないと、テキストボックスに入力した値はタブやリターンを押して確定しないと保存されないようなので注意する。

これで保存するだけ。Bind to: にチェックを入れた時点で、nib ファイルに Shared User Defaults Controller が追加される。

Check Box

Checkbox も同じようにするだけ。これは、チェックが入ったり消えたりした時点で値が保存される(boolean)ので特別な設定はしなくていいはず。

Pop Up Button

次は、Pop Up Button。これの項目には、いろいろと区別するための値があるので、保存する方法もいろいろある。普通は、Title(表示されるテキスト)か Index(何番目か)で保存しておけばいいけど、Text だと文字列を換えたとき、Index だと項目を入れ替えたり増やしたりしたときに対応できなかったりするので注意する。

どちらでも基本的な設定は同じなので、ここでは Title で保存する方にする。Selected Value で上と同じように設定するだけ。Index の場合は、Selected Index で同じように設定するだけ。

Color Well

最後(今のところ)は、ColorWell。これは、もう一つ設定する項目が増える。基本的には同じように設定するんだけど、Value Transformer で NSUnarchiveFromData を選ぶ。

こんな感じになっていればいい。

これだけで、環境設定ウィンドウの項目の値を変えると、それが保存され次に起動したときに反映される。

初期設定ファイルは、ユーザーフォルダの Library -> Preferences に保存されている。ファイル名は、Info.plist の Bundle Identifier にある名前になっている。これを変えると、Preferences ファイルの名前も変わる。

中身はこんな感じ。

Array Controller

ここでは、ちょっと応用編で、Array Controller に蓄積されたデータを User Defaults に保存する方法。

Shared User Defaults のバインドは、Content Array にして、Model Key Path を設定する。そしてもう一つ重要なのが、Handles Content As Compound Value にチェックを入れて、Value Transformer で、NSUnarchiveFromData を選ぶ。これをすることによって、Array Controller の配列が、まとめて Shared User Defaults に保存される。Array Controller のところにもう少し詳しく書いてある。

これとは別に、Handles Content As Compound Value にチェックを入れないで、Value Transformer をブランクにしておくと、Array でそのまま値が保存される。数が少ない場合や、初期値を設定したい場合(変更する可能性が多い場合)などは、Array のままで、扱った方がいいかも。

Object Controller

Object Controller も Array Controller と同じような感じで、Shared User Defaults のバインドは、Content Object にして、Model Key Path を設定する。そして、Handles Content As Compound Value にチェックを入れて、Value Transformer で、NSUnarchiveFromData を選ぶ。このように Data で保存する場合、初期値を設定するのがちょっと面倒になる。初期値を設定する必要がない場合は、UserDefaults.plist に何も設定しないでおく。

これとは別に、Handles Content As Compound Value にチェックを入れないで、Value Transformer をブランクにしておくと、Dictionary で値がそのまま保存される。初期値も Dictionary で指定できるのでわかりやすい。この方法は、Object Controller を使ってみるの最後のあたりにメモってある。

スクリプトからの呼び出し

Shared User Defaults の値をアプリケーションの他の部分で使いたい場合は、そのパーツを Shared User Defaults にバインドすればいいんだけど、ものによってはバインドできないものもある。例えば、NSTextView の背景色を変えたい場合なんか。

Shared User Defaults に入ってる値を得るには、NSUserDefaultsstandardUserDefaults というメソッドを使ってオブジェクトを作る。

defaults = NSUserDefaults.standardUserDefaults

これは、arrayForKey、boolForKey、dataForKey、dictionaryForKey、floatForKey、integerForKey、objectForKey、stringArrayForKey、stringForKey など中に入っている値の方を指定して取り出せる。ただ、Ruby の Hash としても扱えるので、上の方の例で textField という key の値を取り出すには次のようにも書ける。

textFieldValue = defaults["textField"]

普通に値が入っているものはただ取り出せばいいけど、 Color Well なんかの色の情報は NSUnarchiveFromData という Value Transformer を使って NSData で保存されているので、それを読み込めるようにしないといけない。これには、NSUnarchiverunarchiveObjectWithData(data) というメソッドを使う。これで、NSData の色情報が NSColor に変換されるので、NSTextView の背景色を環境設定からいじれる。

@textView.setBackgroundColor(NSUnarchiver.unarchiveObjectWithData(defaults["bgColor"]))

ここで、カラースペースが違う、なんてエラーが出る場合がある。そんなときは、NSColor の colorUsingColorSpaceName というメソッドで、カラースペースを変換するといい。

@textView.setBackgroundColor(NSUnarchiver.unarchiveObjectWithData(defaults["bgColor"]).colorUsingColorSpaceName(NSCalibratedRGBColorSpace))

これ以外のカラースペースについては、このページでちょっと触れている。

ただ、普通に設定するだけだと Text View がでているときに色を変えても反映されない。そこでちょっと工夫する。NSWindow には windowDidBecomeKey(notification) という delegate メソッドがあるので、Text View が乗っかってるウィンドウの delegate を AppController にして(setDelegate(delegate) で設定してもいい)、windowDidBecomeKey(notification) でウィンドウが key になったときつまり前面に出たときに設定が反映されるようにする。

ここでは、@window に @textView という Text View を作って、背景色を bgColor という key で保存されている色に変えるためのサンプルを書いておく。

def windowDidBecomeKey(notification)

defaults = NSUserDefaults.standardUserDefaults

@textView.setBackgroundColor(NSUnarchiver.unarchiveObjectWithData(defaults["bgColor"]))

end

Shared User Defaults の値をアプリケーション初回起動時に設定する

せっかく Shared User Defaults で値を保存するようにしても、最初に起動するときには何も値がないので、いろいろ不都合が出る。そこで、Shared User Defaults の初期値を設定したファイルを作って、それを読み込むようにする。

まず、Xcode で、Property List ファイルを追加する。Resources を右クリックして、新規ファイル... を選ぶ。

テンプレートファイルで、Resource から Property List を選ぶ。

これを UserDefaults.plist と名前を付けて保存する(別の名前でもいいと思うけど、その場合は後でファイル名のところを変える)。

これで、Shared User Defaults に保存するものの初期値を追加していく。

Type は必要にあわせて変える。テキストは String、Index なんかは Number、チェックボックスは Boolean、あと、Array や Dictionary も設定できる。ただ、Array や Dictionary は Color Well と同じように Data を選んで、まとめて保存した方がいいかもしれない。

必要なものをすべて追加したら、これを読み込む部分を awakeFromNib に書き込む。

def awakeFromNib

userDefaultsFilePath = NSBundle.mainBundle.pathForResource_ofType("UserDefaults","plist")

userDefaultsValues = NSDictionary.dictionaryWithContentsOfFile(userDefaultsFilePath)

NSUserDefaults.standardUserDefaults.registerDefaults(userDefaultsValues)

end

一行目の UserDefaults のところがファイル名なので、別のファイル名を使う場合はここを変える。これで、初回に起動したときや、起動してから変更をしなかった値などがこのファイルから初期値として読み込まれる。