CoreData: Documentsフォルダ以外にsqliteファイルを置く


iTunesのAppタブにあるファイル共有を使う場合、アプリのDocumentsフォルダがその共有対象になる。ところが CoreDataを使っている場合、そのデータベースファイルもデフォルトではDocumentsフォルダに生成されるので、これがiTunesから見えてしまうという問題がある。CoreDataのファイルを別の場所に置く方法について調べたので以下にまとめておく。

ちなみに、iTunesのAppタブのファイル共有で共有できるようにする方法は、Xcode4ではTARGETアプリのInfo(XXXX-Info.plist)に”Application supports iTunes file sharing”というタグを追加して(Xcode4でポップアップから選ぶだけ)、これをYESにすればよい。

さて、まず Documentsフォルダ以外に置くならどこに置けばよいのか。
Core Data and iTunes File Sharing – Move/hide the .sqlite file on app update?
の議論によると、そのアプリのフォルダ下の NSApplicationSupportDirectory すなわち /Library/Application Support フォルダがよいようだ。

次に、この変更をプログラムのどこで指定すればいいのか。MyAppというプロダクトなら、最初に動く、MyAppAppDelegate.m があって、この中に storeに関する以下のmethodがある。
– (NSPersistentStoreCoordinator *)persistentStoreCoordinator { … }
この中で、デフォルトでは以下のようにsqliteファイルのURLが設定されている。

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@”MyApp.sqlite”];

これの[self applicationDocumentsDirectory] がDocumentsフォルダへのパスを返しているのだとわかる。これを/Library/Application Support フォルダを返すものに変えればいいわけだ。

重要なヒントは以下のサイトに書かれていた。
Where to Store Persistent Files in iOS 4?

NSApplicationSupportDirectoryを取得するメソッド applicationSupportDirectoryを作って、上記のデフォルトの [self applicationDocumentsDirectory] を[self applicationSupportDirectory] に差し替えればよいと書かれているのだとわかる(実際はNSStringをNSURLにも変えなければならない:後述)。

ここに書かれているサンプルコードでは、親切にも/Library/Application Support フォルダがまだない場合は生成する処理も書いてある。ところが惜しいことに、ここに書かれているcreateDirectoryAtPathの記述は少しだけ間違っている。また、NSStringもNSURLにしなければならない。

以下のページを参考にさせていただくと下のコードのようになるようだ。
Persistent store migration failed missing source managed object model

ここでは applicationSupportDirectory というメソッドを作らずに直接書く形にした。

NSString *applicationSupportDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
NSError *error = nil;
if ( ![[NSFileManager defaultManager] fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
  if (![[NSFileManager defaultManager]
        createDirectoryAtPath:applicationSupportDirectory
        withIntermediateDirectories:NO
        attributes:nil
        error:&error]) {
    NSAssert(NO, ([NSString stringWithFormat:@”Failed to create App Support directory %@ : %@”, applicationSupportDirectory,error]));
    NSLog(@”Error creating application support directory at %@ : %@”,applicationSupportDirectory,error);
    return nil;
  }
}
NSURL *storeURL = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @”MyApp.sqlite”]];

もともとあった

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@”MyApp.sqlite”];

を、上記の数行に置き換えることで、/Library/Application Support フォルダにsqliteファイルを置くようにすることができる。

蛇足:NSApplicationSupportDirectoryでのフォルダ生成について調べていたら、以下のようなツールを提供しているサイトを見つけた。
Finding or creating the application support directory
とても便利なツールで、このサイトから
NSFileManager+DirectoryLocations.h
NSFileManager+DirectoryLocations.m
をダウンロードして、自分のプロジェクトに組み込み、
#import “NSFileManager+DirectoryLocations.h”
して、後は、
NSString *path = [[NSFileManager defaultManager] applicationSupportDirectory];
とやるだけで、必要なフォルダのパスが返ってくるだけでなく、もしフォルダがなければ自動生成してくれる。ただし、これはどうもマックのアプリ用だと思う。と言うのも、返ってくるのは/Library/Application Supportにさらにアプリの名前を付けたフォルダ名、例えば/Library/Application Support/MyApp フォルダとなるようにできているからだ。
いつか使う日が来るかも知れないのでここにメモっておく。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中