14468


アプリver1でCoreDataのリストアプリを作成済みで、今回のver2でファイル共有機能を追加したいと思っています。けれど、ファイル共有でsqliteファイルがユーザーから見えてしまうので、sqliteの置き場所を変更しようと思います。

[code]

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {    
        略)
      NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];
        略）
    }
    
[/code]

上の処理を書き換えて下のようにしました。

[code]

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        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"]];
    }
    
[/code]

このようにしてみましたが、新規ダウンロードの場合は上手くいくと思うのですがアップデートの際に問題が残ります。

既存のsqliteの移行処理はどのようにしたらよいのでしょうか?

追記 8/17 23:24  
いただいたコメントを元に実装してみました。書く位置によってハマるところがあったり、iOS7移行は sqlite.shm やsqlite.wal
などのファイルもあってかなり苦労したのでうまくいった例として  
掲載します。  
sqlite,sqlite.shm,sqlite.wal
ファイル共有から丸見え状態→プログラム書き換え→ビルド→ファイル隠し成功&sqliteデータの引き継ぎ成功→ビルド→問題なし。まで確認しました。

[code]

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
    //meta dataを取得する
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    
    
      // Create the coordinator and store
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
     NSDictionary *options = @{NSInferMappingModelAutomaticallyOption:@YES,
                              NSMigratePersistentStoresAutomaticallyOption:@YES};
    //sqlite移行処理
    
    NSURL *oldStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];
    NSURL *oldStoreURL_shm = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite-shm"];
    NSURL *oldStoreURL_wal = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite-wal"];
    
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    NSString *applicationSupportDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
    //移行用ディレクトリがなければ新たに作成
    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_shm = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @"MyApp.sqlite-shm"]];
    NSURL *storeURL_wal = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @"MyApp.sqlite-wal"]];
    
    
    NSFileManager *fileManager = [[NSFileManager alloc]init];
    //今までの保存先にファイルがあれば移行処理に入る
    if ([fileManager fileExistsAtPath:oldStoreURL.path]) {
        NSPersistentStore *oldStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                                configuration:nil
                                                                                          URL:oldStoreURL
                                                                                      options:options
                                                                                        error:nil];
        // 新しい場所にコピー
        [_persistentStoreCoordinator migratePersistentStore:oldStore
                                                      toURL:storeURL
                                                    options:options
                                                   withType:NSSQLiteStoreType
                                                      error:nil];
        //shmとwalを移行用のURLにコピー
        [fileManager copyItemAtURL:oldStoreURL_shm toURL:storeURL_shm error:nil];
        [fileManager copyItemAtURL:oldStoreURL_wal toURL:storeURL_wal error:nil];
        //移行前のsqlite本体を削除
        [fileManager removeItemAtURL:oldStoreURL error:nil];
        //移行前のshmとwalを削除
        [fileManager removeItemAtURL:oldStoreURL_shm error:nil];
        [fileManager removeItemAtURL:oldStoreURL_wal error:nil];
    
    //この下の文を if(~ )のままにすると、評価式に入って2度 
    //-(addPersistentStoreWithType:略)が呼び出されることになりアプリが落ちるので、else if にしておきます。
    //一度正常に動けば上のif文は通過しないためバグは起きません。
    }else if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
    
    
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    
    return _persistentStoreCoordinator;
    }
    
[/code]


CC BY-SA 3.0
2015-08-16T03:24:40.200
14457
2015-08-28T13:42:50.347
2015-08-28T13:42:50.347
8320
8320
question
ios objective-c coredata
CoreDataのsqliteデータをファイル共有で見えないように移行する


アップルが推奨する方法は`-[NSPersistentStoreCoordinator migratePersistentStore:
toURL:options:withType:error:]`を使うことです。

<https://developer.apple.com/library/ios/qa/qa1809/_index.html>

古い`NSPersistentStore`オブジェクトについて新しいファイルパスを渡すと、必要なファイルをすべてコピーしてくれます。

たとえば、下記のようにします。

[code]

    // 古いファイルパス
    NSURL *oldStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];
    
    // 新しいファイルパス
    NSString *applicationSupportDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
    NSURL *storeURL = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @"MyApp.sqlite"]];
    
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    // 古いファイルがあったら
    if ([fileManager fileExistsAtPath:oldStoreURL.path]) {
        NSPersistentStore *oldStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                                configuration:nil
                                                                                          URL:oldStoreURL
                                                                                      options:nil
                                                                                        error:nil];
        // 新しい場所にコピー
        [_persistentStoreCoordinator migratePersistentStore:oldStore
                                                      toURL:storeURL
                                                    options:nil
                                                   withType:NSSQLiteStoreType
                                                      error:nil];
    
        // 古いファイルを消す
        [fileManager removeItemAtURL:oldStoreURL error:nil];
    }
    
[/code]

または、`NSFileManager`APIを使って、一つずつ必要なファイルをコピーしていくのでもいいです。


CC BY-SA 3.0
2015-08-16T08:39:27.007
14468
2015-08-16T08:39:27.007
5519
14457
answer