AppSandBoxとNSSavePanelの関係
AppSandBoxとNSOpen/NSSavePanelの関係について今ひとつはっきりしていなかったので、ごく簡単なXcodeProjectで確認してみた。
確認に使った環境等
- Xcode Version 8.3.3 (8E3004b)
- macOS Version 10.12.5 (16F73)
- MacBook Pro 10.1および13.1
- 確認に使ったコード
-
- (IBAction)saveFile:(id)sender { NSString *logFile = @"A Test String to save LogFile."; NSError *anError = nil; NSDateFormatter *format = [[NSDateFormatter alloc] init]; [format setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"]]; [format setDateFormat:@"yyyyMMdd-HHmmss"]; NSString *stringTime = [format stringFromDate:[NSDate date]]; NSString *logFileName = [NSString stringWithFormat:@"Wing Go Client Log - %@",stringTime]; NSSavePanel *savePanel = [NSSavePanel savePanel]; [savePanel setAllowedFileTypes:[NSArray arrayWithObject:@"txt"]]; [savePanel setAllowsOtherFileTypes:NO]; [savePanel setNameFieldStringValue:logFileName]; [savePanel setMessage:NSLocalizedString(@"Select the place to save Logfile", @"Select the place to save Logfile")]; if ([savePanel runModal] == NSFileHandlingPanelOKButton) { NSURL *selectedURL = [savePanel URL]; NSString *selectedFile = [selectedURL path]; BOOL logSuccess= [logFile writeToFile:selectedFile atomically:YES encoding:NSUTF8StringEncoding error:&anError]; if(!logSuccess) { //Don’t look at an NSError unless you konw that something failed! if (anError) { NSLog(@"Error creating file: %@",anError); anError = nil; return; } } } }
以下の条件で確認、結果を併記している。
-
AppSandBox設定なし
- 書類(Documents)フォルダがデフォルトの保存先になっている。
- ファイルの保存ができる。Usersの共有(shared)にも保存できる。
- 選択した保存先は、アプリケーションを終了しても記憶されている。
-
Xcodeのコンソールエリアに
Failed getting container for URL…
というエラーが出る。
-
AppSandBox設定のみ
-[NSVBSavePanel init] caught non-fatal NSObjectNotAvailableException…
というExceptionが出て、ファイルも保存できない。 -
AppSandBox設定プラスUser Selected Fileの読み書き許可
- 書類(Documents)フォルダがデフォルトの保存先になっている。
- ファイルの保存ができる。Usersの共有(shared)にも保存できる。
- 選択した保存先は、アプリケーションを終了しても記憶されている。
-
上記の条件でmyLogFileというフォルダにファイルを保存、そのフォルダをFinderで別の場所に移動
myLogFileの記憶は失われ、デフォルトの書類(Documents)フォルダにリセットされる。
-
NSURLのブックマーク機能の追加
UserDefaultsに、ユーザーが選択したログファイル保存先のURLではなく、bookmarkに変換したものを保存し、それを解読してsetDirectoryURLするように変更した。bookmarkはsecurity-scopedではない、普通のものである。- 改造したコード
-
- (IBAction)save:(id)sender { NSString *logFile = @"A Test String to save LogFile."; NSString *aLogDirectory = nil; NSData *aBookMark = nil; NSData *bBookMark = nil; NSURL *aBookmarkedURL = nil; NSURL *bLogDirectoryURL = nil; NSError *anError; BOOL isDir; NSFileManager *aManager = [NSFileManager defaultManager]; // Set default directory NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docDir = [paths objectAtIndex:0]; aLogDirectory = docDir; aBookMark = [defaults objectForKey:@"logBookMark"]; if (aBookMark.length != 0) { aBookmarkedURL = [NSURL URLByResolvingBookmarkData:aBookMark options:0 relativeToURL:nil bookmarkDataIsStale:nil error:&anError]; if (aBookmarkedURL != NULL) { aLogDirectory = [aBookmarkedURL path]; if ([aManager fileExistsAtPath:aLogDirectory isDirectory:&isDir]) { if (!isDir) aLogDirectory = docDir; } } else { if (anError) { NSLog(@"Error resolving bookmark: %@",anError); anError = nil; return; } } } NSDateFormatter *format = [[NSDateFormatter alloc] init]; [format setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"]]; [format setDateFormat:@"yyyyMMdd-HHmmss"]; NSString *stringTime = [format stringFromDate:[NSDate date]]; NSString *logFileName = [NSString stringWithFormat:@"Wing Go Client Log - %@",stringTime]; NSSavePanel *savePanel = [NSSavePanel savePanel]; [savePanel setAllowedFileTypes:[NSArray arrayWithObject:@"txt"]]; [savePanel setAllowsOtherFileTypes:NO]; [savePanel setNameFieldStringValue:logFileName]; [savePanel setDirectoryURL:[NSURL fileURLWithPath:aLogDirectory]]; [savePanel setMessage:NSLocalizedString(@"Select the place to save Logfile", @"Select the place to save Logfile")]; if ([savePanel runModal] == NSFileHandlingPanelOKButton) { NSURL *selectedURL = [savePanel URL]; NSString *selectedFile = [selectedURL path]; BOOL logSuccess= [logFile writeToFile:selectedFile atomically:YES encoding:NSUTF8StringEncoding error:&anError]; if(!logSuccess) { //Don’t look at an NSError unless you konw that something failed! if (anError) { NSLog(@"Error creating file: %@",anError); anError = nil; return; } } bLogDirectoryURL = [NSURL fileURLWithPath:[selectedFile stringByDeletingLastPathComponent]]; bBookMark = [bLogDirectoryURL bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile includingResourceValuesForKeys:nil relativeToURL:nil error:&anError]; if (bBookMark != NULL) { [defaults setObject:bBookMark forKey:@"logBookMark"]; [defaults synchronize]; } else { if (anError) { NSLog(@"Error creating Bookmark: %@",anError); anError = nil; return; } } } }
- 書類(Documents)フォルダがデフォルトの保存先になっている。(そう設定した)
- ファイルの保存ができる。Usersの共有(shared)にも保存できる。
- 選択した保存先は、アプリケーションを終了しても記憶されている。
- 保存先のフォルダを移動しても追従する。
「なるほど、なるほど。」と言いたいところだが、
Usersの共有(shared)フォルダというのは、AppSandBoxが用意するアプリケーション専用のコンテナ(砂場)の外ではないのか?
security-scoped bookmarkを使うのはどんな条件なんだ?
という疑問が残る。
Appleの公式ドキュメントを読んでも、頭が悪い筆者には理解できなかった。誰か教えて欲しい!!
この投稿へのトラックバック
トラックバックはありません。
- トラックバック URL
この投稿へのコメント