0

アプリでコアデータを使用しており、次の更新で iTunes ファイル共有を開始したいのですが、最初にアプリの sqlite データベースを移動する必要があります。以下のコードを試してみましたが、起動時にアプリがクラッシュします。NSPersistentStoreCoordinator で古いストアの URL を新しいストアの URL に置き換えるだけでよいと思いました。ここで、「newDatabasePath」は新しいストアの URL と一致します。

次に、sqliteファイルを次のように置き換えます

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//check app has run before and has a current db
if ([saveData boolForKey:@"hasRunBefore"]) {
NSString *oldDatabasePath = [[dirPaths objectAtIndex:0] stringByAppendingPathComponent:@"AppData.sqlite"];
        NSString *newDatabasePath = [privateDocsPath stringByAppendingPathComponent:@"AppData.sqlite"];
        NSError *error;
        if ([fileMgr fileExistsAtPath:newDatabasePath]) {

            [fileMgr removeItemAtPath:newDatabasePath error:&error];
            [fileMgr copyItemAtPath:oldDatabasePath toPath:newDatabasePath  error:&error];
        }

        [fileMgr removeItemAtPath:oldDatabasePath error:&error];

        BOOL databaseMoved = YES;
        [saveData setBool:databaseMoved forKey:@"databaseMoved"];
}
}

ありがとう

ここで同様の質問を読んだ後、これを解決するための新しいアプローチを試みました。私はそのようにcoredataスタックをリセットしようとしました

- (void)resetDatabase {

NSPersistentStore* store = [[__persistentStoreCoordinator persistentStores] lastObject];

NSError *error = nil;
NSURL *storeURL = store.URL;

// release context and model
__managedObjectModel = nil;
__managedObjectContext = nil;

//[__persistentStoreCoordinator removePersistentStore:store error:nil];

__persistentStoreCoordinator = nil;

NSFileManager* fileMgr = [NSFileManager defaultManager];
[fileMgr removeItemAtPath:storeURL.path error:&error];
if (error) {
    NSLog(@"filemanager error %@", error);
}

NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

//create Private Documents Folder
NSArray *libPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libDir = [libPaths objectAtIndex:0];
NSString *privateDocsPath = [libDir stringByAppendingPathComponent:@"Private Documents"];
if (![fileMgr fileExistsAtPath:privateDocsPath])
    [fileMgr createDirectoryAtPath:privateDocsPath withIntermediateDirectories:YES attributes:nil error:nil];


NSString *oldDatabasePath = [[dirPaths objectAtIndex:0] stringByAppendingPathComponent:@"AppData.sqlite"];
NSString *newDatabasePath = [privateDocsPath stringByAppendingPathComponent:@"AppData.sqlite"];

BOOL removedItemAtPath = NO;
BOOL copiedItemToPath = NO;

if ([fileMgr fileExistsAtPath:newDatabasePath]) {
    DLog(@"DATABASE EXISTS AT PATH");
    removedItemAtPath = [fileMgr removeItemAtPath:newDatabasePath error:&error];
    if (removedItemAtPath) {
        DLog(@"ITEM REMOVED");
    }
    else
        DLog(@"FAILED TO REMOVE ITEM: %@", error);

    copiedItemToPath = [fileMgr copyItemAtPath:oldDatabasePath toPath:newDatabasePath  error:&error];
    if (copiedItemToPath) {
        DLog(@"ITEM COPIED");
    }
    else
        DLog(@"FAILED TO COPY ITEM: %@", error);
}

// recreate the stack
__managedObjectContext = [self managedObjectContext];

}

このアプローチでは、アプリを最初に起動したときにコアデータ スタックからデータを読み込もうとすると例外がスローされますが、その後、すべてが正常にリロードされ、「ライブラリ/プライベート ドキュメント」の新しい場所から sqlite ファイルが使用されます。

4

3 に答える 3

0

あなたが言ったので、エラーメッセージは次のとおりです。

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array' *** First throw call stack:

それは、この行にかなり強く指を向けています:

NSString *oldDatabasePath = [[dirPaths objectAtIndex:0] stringByAppendingPathComponent:@"AppData.sqlite"];

エラー メッセージには、空の配列でインデックス 0 を使用している理由も示されています。だから、dirPaths空です。値を指定するコードを投稿しなかったため、理由はわかりませんが、それがこのクラッシュの原因です。

于 2013-08-02T16:13:12.197 に答える
0

答えはいつものように簡単であることが判明しました!

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions から実行しようとするのではなく、ストアが追加される前に、アプリの元のデータベースを - (NSPersistentStoreCoordinator *)persistentStoreCoordinator にコピーするために必要なコードを移動しました。 .

また無駄な日が続く!

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{

if (__persistentStoreCoordinator != nil)
{
    return __persistentStoreCoordinator;
}

//test if app already run before, copy database over and remove old one, finally switch store url to new directory
if ([saveData boolForKey:@"hasRunBefore"]) {

    if ([saveData boolForKey:@"databaseUpdated"] != YES) {

        DLog(@"MOVING DATABASE");
        NSFileManager* fileMgr = [[NSFileManager alloc] init];
        fileMgr.delegate = self;
        NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docsDir = [dirPaths objectAtIndex:0];
        //create Private Documents Folder
        NSArray *libPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
        NSString *libDir = [libPaths objectAtIndex:0];
        NSString *privateDocsPath = [libDir stringByAppendingPathComponent:@"Private Documents"];
        if (![fileMgr fileExistsAtPath:privateDocsPath])
            [fileMgr createDirectoryAtPath:privateDocsPath withIntermediateDirectories:YES attributes:nil error:nil];

        NSString *oldDatabasePath = [docsDir stringByAppendingPathComponent:@"AppData.sqlite"];
        NSString *newDatabasePath = [privateDocsPath stringByAppendingPathComponent:@"AppData.sqlite"];
        NSError *error;
        //BOOL removedItemAtPath = NO;
        BOOL copiedItemToPath = NO;

        copiedItemToPath = [fileMgr copyItemAtPath:oldDatabasePath toPath:newDatabasePath  error:&error];
        if (copiedItemToPath) {
            DLog(@"ITEM COPIED");
        }
        else
            DLog(@"FAILED TO COPY ITEM: %@", error);

        [fileMgr removeItemAtPath:oldDatabasePath error:&error];

        [saveData setBool:YES forKey:@"databaseUpdated"];
        [saveData synchronize];

    }

}


//NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"AppData.sqlite"];
NSURL *storeURL = [[self applicationHiddenDocumentsDirectory] URLByAppendingPathComponent:@"AppData.sqlite"];

NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
    DLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}    

return __persistentStoreCoordinator;
}
于 2013-08-03T07:55:25.980 に答える