PaTrash2.0を作る - その8 [プログラミング]
なかなか進まないPaTrash2.0。前回はもうひと月前になってしまった。もうすっかり忘れてしまっている。
ヘッドレスアプリ(ユーザインターフェイスを持たないエージェントプロセス)のパラメータ設定のために、PaTras1.0では専用のアプリを作ったが、2.0ではユーザレベルのシステム環境設定にしたい。前回、システム環境設定はインターフェイスAPIのほとんどないプラグインを作るのと同じでいい、というのがわかった。今日は環境設定のファイル(バンドル)がどこにあるかで影響する範囲が違う(設定したユーザだけなのか、ローカルなシステム全体か、またネットワークに影響するか、などなど)が、それをプログラムからどうやって探すかを整理する。
となっている(表がLaTeXの出力より見づらいな)。PaTrash2.0のように個々のユーザごとに使ったり使わなかったりする環境設定は一番最後のディレクトリに置くことになる。ちなみにシステム環境設定のアプリはこの下から順番に登録していく。同じディレクトリに同じバンドル識別子(Bundle Indentifier Code)のバンドルがあった時は、後のものが無視されることになるらしい。
一般にMac OS Xでは影響の範囲をドメイン(domain)と呼んでいて、他のディレクトリに対しても同じようにアクセスされる。ドメインを指定するためにはNSSearchPathDomainMaskという定数
例えば環境設定ペインを入れておくディレクトリのパスはOSのバージョンによって変更されるということはまずないはずなので、ハードコードしても問題ないと思われる。しかし、10.7Lionから導入されたサンドボックスに対応しようとすると、パスのハードコードは避けなければいけない。
そのために、いくつかの方法が提供されている。
まずNSFileManagerを使う方法。
NSSearchPathDirectory型は
ドメインによっては意味がない場合もあって、そのときは空っぽのNSArrayが返る。
NSFilemanager以外にFoundationの関数がある。
またこれ以外に特別なパスを返す
ただし、URLsForDirectory:inDomains:メソッドもこれらの関数もパスが実際に存在することを保証するわけではない。Mac OS Xではほとんどありえないけど、まれにユーザがディレクトリを削除してしまっている、ということも考えられるので、このあとNSFileManagerのメソッド
もし「なければ作る」という動作が必要ならNSFileManagerの
アプリがユーザプロセスで、システムドメインのディレクトリを作ろうとする場合などはNSErrorのインスタンスが作られてエラーが返ることになる。
ヘッドレスアプリ(ユーザインターフェイスを持たないエージェントプロセス)のパラメータ設定のために、PaTras1.0では専用のアプリを作ったが、2.0ではユーザレベルのシステム環境設定にしたい。前回、システム環境設定はインターフェイスAPIのほとんどないプラグインを作るのと同じでいい、というのがわかった。今日は環境設定のファイル(バンドル)がどこにあるかで影響する範囲が違う(設定したユーザだけなのか、ローカルなシステム全体か、またネットワークに影響するか、などなど)が、それをプログラムからどうやって探すかを整理する。
7.3 環境設定の位置
環境設定はそのバンドルをどこに置くかで使われ方が違う。それはディレクトリ | 説明 |
/System/Library/PreferencePanes | Mac OS X の組み込みの環境設定 |
/Network/Library/PreferencePanes | ネットワーク上のすべてのユーザーが利用可能な環境設定 |
/Library/PreferencePanes | ローカルなコンピューター上で利用可能な環境設定 |
~/Library/PreferencePanes | 現在のユーザーだけで利用可能な環境設定 |
となっている(表がLaTeXの出力より見づらいな)。PaTrash2.0のように個々のユーザごとに使ったり使わなかったりする環境設定は一番最後のディレクトリに置くことになる。ちなみにシステム環境設定のアプリはこの下から順番に登録していく。同じディレクトリに同じバンドル識別子(Bundle Indentifier Code)のバンドルがあった時は、後のものが無視されることになるらしい。
一般にMac OS Xでは影響の範囲をドメイン(domain)と呼んでいて、他のディレクトリに対しても同じようにアクセスされる。ドメインを指定するためにはNSSearchPathDomainMaskという定数
enum { NSUserDomainMask = 1, NSLocalDomainMask = 2, NSNetworkDomainMask = 4, NSSystemDomainMask = 8, NSAllDomainsMask = 0x0ffff, }; typedef NSUInteger NSSearchPathDomainMask;を使うようになっている。
例えば環境設定ペインを入れておくディレクトリのパスはOSのバージョンによって変更されるということはまずないはずなので、ハードコードしても問題ないと思われる。しかし、10.7Lionから導入されたサンドボックスに対応しようとすると、パスのハードコードは避けなければいけない。
そのために、いくつかの方法が提供されている。
まずNSFileManagerを使う方法。
- (NSArray *)URLsForDirectory:(NSSearchPathDirectory)directory inDomains:(NSSearchPathDomainMask)domainMask;これは10.6で追加されたメソッドで、NSURLの配列を返す。domainMaskにはさっきのNSSearchPathDomainMaskを指定する。論理和で複数を指定してもいい。そのときはNSSearchPathDomainMaskの値の小さい順番にNSArrayに格納される。
NSSearchPathDirectory型は
enum { NSApplicationDirectory = 1, NSDemoApplicationDirectory, NSDeveloperApplicationDirectory, NSAdminApplicationDirectory, NSLibraryDirectory, NSDeveloperDirectory, NSUserDirectory, NSDocumentationDirectory, NSDocumentDirectory, NSCoreServiceDirectory, NSAutosavedInformationDirectory = 11, NSDesktopDirectory = 12, NSCachesDirectory = 13, NSApplicationSupportDirectory = 14, NSDownloadsDirectory = 15, NSInputMethodsDirectory = 16, NSMoviesDirectory = 17, NSMusicDirectory = 18, NSPicturesDirectory = 19, NSPrinterDescriptionDirectory = 20, NSSharedPublicDirectory = 21, NSPreferencePanesDirectory = 22, NSItemReplacementDirectory = 99, NSAllApplicationsDirectory = 100, NSAllLibrariesDirectory = 101 }; typedef NSUInteger NSSearchPathDirectory;のようなもので、だいたい読んで字のごとしで、どれかを指定する。ドメインの指定との組み合わせで、異なるファイルのURLが返される。たとえばNSApplicationDirectoryで、NSUserDomainMaskを指定すると ∼ /Applicationsディレクトリが、NSLocalDomainMaskだと/Applicationsが返される。
ドメインによっては意味がない場合もあって、そのときは空っぽのNSArrayが返る。
NSFilemanager以外にFoundationの関数がある。
NSArray * NSSearchPathForDirectoriesInDomains ( NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);これは基本的にはNSFileManagerのURLsForDirectory:inDomains:メソッドと同じことをする。ただし、こっちはNSURLのインスタンスではなくてパスの文字列(NSStringのインスタンス)になっている。
またこれ以外に特別なパスを返す
NSString * NSHomeDirectory (void); NSString * NSHomeDirectoryForUser (NSString *userName); NSString * NSTemporaryDirectory (void);なんかがある。
ただし、URLsForDirectory:inDomains:メソッドもこれらの関数もパスが実際に存在することを保証するわけではない。Mac OS Xではほとんどありえないけど、まれにユーザがディレクトリを削除してしまっている、ということも考えられるので、このあとNSFileManagerのメソッド
- (BOOL)fileExistsAtPath:(NSString *)path; - (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory; - (BOOL)isReadableFileAtPath:(NSString *)path; - (BOOL)isWritableFileAtPath:(NSString *)path; - (BOOL)isExecutableFileAtPath:(NSString *)path; - (BOOL)isDeletableFileAtPath:(NSString *)path;などのメソッドで必要な属性を判断する必要がある。
もし「なければ作る」という動作が必要ならNSFileManagerの
- (NSURL *)URLForDirectory:(NSSearchPathDirectory)directory inDomain:(NSSearchPathDomainMask)domain appropriateForURL:(NSURL *)url create:(BOOL)shouldCreate error:(NSError **)error;を使う。shouldCreateフラグをYESにすると、存在しない場合作られる。url引数はユーザのテンポラルなディレクトリを作りたい時にだけ(directoryがNSItemReplacementDirectoryでかつdomainが NSUserDomainMaskのときだけ)利用されて、それ以外は無視される。
アプリがユーザプロセスで、システムドメインのディレクトリを作ろうとする場合などはNSErrorのインスタンスが作られてエラーが返ることになる。
2012-07-24 17:28
nice!(0)
コメント(0)
トラックバック(0)
コメント 0