ページ

2009年12月22日火曜日

SimpleCap - ファイル更新反映

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

(前回)Cocoaの日々: FSEvent - フォルダを監視する

SimpleCap へフォルダ監視の仕組みを導入して他のアプリでの変更を表示に反映するようにした。


例えば、まずキャプチャを行う。


プレビューを開き、画像を加工する。ここではグレースケール化して保存する。

数秒後に SimpleCap が変更を検出してメッセージを表示する。

表示中の画像も最新のものに置き換わる。


アプリ実装時の注意点など


プリファレンスで保存先が変更になった場合
KVOなどを使って検出し、一旦以前の FSEvent を破棄した後、再登録する。
破棄例:

if (_fsevent_stream) {
FSEventStreamStop(_fsevent_stream);
FSEventStreamInvalidate(_fsevent_stream);
}


ファイルが更新されたどうかの確認
FSEvent はフォルダ単位での更新しかわからないので、表示中のファイルが更新されたかどうかは自分で調べる必要がある。SimpleCap では表示中の画像の最終更新日時をとっておき、FSEvent が発生した時に比較している。

他の操作との整合性(新規作成、削除、名前変更など)
フォルダ更新は、上記のファイル更新のほかキャプチャ後の新規作成や、削除、名前更新などさまざまな操作によって通知される。これらの操作と目的のファイル更新時の処理とが矛盾なく動作するように調整する必要がある。今回は先の最終更新日時の比較だけでうまく動いている。

Nib経由で NSUserDefaultsを取得する場合
FSEvent へ登録するパスを Nib内のNSUserDefaultsController から取得している場合、FSEvent登録タイミングに Nibの読み込みが終わっていないとパスが nilとなり登録に失敗する(あたりまえだが)。
SimpleCap[28181] (CarbonCore.framework) FSEventStreamCreate: _FSEventStreamCreate: ERROR: could not allocate 0 bytes for array of path strings
SimpleCap[28181] (CarbonCore.framework) FSEventStreamScheduleWithRunLoop(): failed assertion 'streamRef != NULL'
  
SimpleCap[28181] (CarbonCore.framework) FSEventStreamStart(): failed assertion 'streamRef != NULL'

この場合は確実に NSUsesrDefaultsController から値が取得できるように、awakeFromNib 内で FSEvent への登録を行う。