【问题标题】:core data can't find model for source store - what did my old store look like?核心数据找不到源存储模型 - 我的旧存储是什么样的?
【发布时间】:2011-04-04 21:21:55
【问题描述】:

因此,首先,this question 在正确处理核心数据版本控制方面帮助很大。所以我为我的模型添加了一个新版本,现在我试图让自动迁移工作,但我有一个问题。我不记得我的旧版本是什么样子了!我正在尝试在手机上运行该应用程序,但我已经使用模拟器一段时间了,并对架构进行了一些更改。手机上的版本是很久以前的了。所以每次我尝试将旧版本修改为我认为在手机上的版本,但我仍然收到“找不到源存储的模型”错误。我猜是因为我弄错了旧架构。

有什么方法可以让我弄清楚手机上的架构是什么样的?除此之外,我怎么能从手机上擦除 sqlite 商店,以便我可以从版本 1 重新开始?

【问题讨论】:

  • 你可以删除手机的应用程序并重新安装,你会得到一个新的应用程序,从而一个新的 sqlite 商店

标签: iphone core-data versioning


【解决方案1】:

使用核心数据迁移使用新架构更新旧数据库,同时丢失数据。

https://developer.apple.com/library/ios/documentation/cocoa/conceptual/CoreDataVersioning/Articles/vmLightweightMigration.html

【讨论】:

    【解决方案2】:

    我一整天都在为“找不到源存储的模型”错误而烦恼。以下是learner2010对google员工的回答:

    • 您的 sqlite 数据库的模型哈希必须与您在构建应用程序时由您的 xcdatamodel 创建的 mom 或 momd 之一匹配。您可以在构建的应用程序包中的 momd 的 VersionInfo.plist 中看到哈希值。请参阅下面的代码以查找数据库的模型哈希。

    • 1234563数据库,它使用旧模型。这就是导致“找不到源存储模型”错误的原因。
    • 更糟糕的是,sqlite 数据库存储在类似“/private/var/mobile/Library/Mobile Documents/YOU_APP_ID/Data.nosync/YOUR_DB.sqlite”的位置,即使您从设备中删除应用程序并重新安装!所以你会认为你的代码有问题,而实际上你只是有一个陈旧的数据库需要删除。通常这是在调试过程中,所以无论如何都没有真正的数据。

    • 因此,未来允许迁移的正确工作流程是创建模型、运行应用程序以构建数据库,然后在需要进行更改时创建模型的新版本。如果您保持较小的更改,一切都会“正常工作”。然后,当您准备好发布您的应用程序时,选择最终模型并删除其余部分。然后从“/private/var/mobile/Library/Mobile Documents”中删除您的数据库。然后在未来的版本中,包括以前版本中的所有模型以及您的最新模型(如果已更改),用户每次都可以迁移。

    到目前为止,这是我的代码。重要的一行是:

    [fileManager removeItemAtPath:iCloudData error:&error];
    

    但它只能在调试期间用于删除旧数据库。这是 AppDelegate.m 中的生产代码:

    - (NSManagedObjectModel *)managedObjectModel
    {
        if (__managedObjectModel != nil)
        {
            return __managedObjectModel;
        }
        //NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
        //__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    
        //NSArray *testArray = [[NSBundle mainBundle] URLsForResourcesWithExtension:@"momd"subdirectory:nil];
    
        NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
    
        if( !path ) path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"mom"];
    
        NSURL *modelURL = [NSURL fileURLWithPath:path];
    
        __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    
        //__managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    
        return __managedObjectModel;
    }
    
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if((__persistentStoreCoordinator != nil)) {
            return __persistentStoreCoordinator;
        }
    
        __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];    
        NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;
    
        // Set up iCloud in another thread:
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
            // ** Note: if you adapt this code for your own use, you MUST change this variable:
            NSString *iCloudEnabledAppID = @"RW6RS7HS69.com.zsculpt.soaktest";
    
            // ** Note: if you adapt this code for your own use, you should change this variable:        
            NSString *dataFileName = @"mydailysoak.sqlite";
    
            // ** Note: For basic usage you shouldn't need to change anything else
    
            NSString *iCloudDataDirectoryName = @"Data.nosync";
            NSString *iCloudLogsDirectoryName = @"Logs";
            NSFileManager *fileManager = [NSFileManager defaultManager];        
            NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
            NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
    
            if (iCloud) {
    
                NSLog(@"iCloud is working");
    
                NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
    
                NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID);
                NSLog(@"dataFileName = %@", dataFileName); 
                NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName);
                NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName);  
                NSLog(@"iCloud = %@", iCloud);
                NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);
    
                if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
                    NSError *fileSystemError;
                    [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
                        withIntermediateDirectories:YES 
                                         attributes:nil 
                                              error:&fileSystemError];
                    if(fileSystemError != nil) {
                        NSLog(@"Error creating database directory %@", fileSystemError);
                    }
                }
    
                NSString *iCloudData = [[[iCloud path] 
                                         stringByAppendingPathComponent:iCloudDataDirectoryName] 
                                        stringByAppendingPathComponent:dataFileName];
    
                NSLog(@"iCloudData = %@", iCloudData);
    
                NSMutableDictionary *options = [NSMutableDictionary dictionary];
                [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
                [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
                [options setObject:iCloudEnabledAppID            forKey:NSPersistentStoreUbiquitousContentNameKey];
                [options setObject:iCloudLogsPath                forKey:NSPersistentStoreUbiquitousContentURLKey];
    
                [psc lock];
            NSError *error;
    
                [psc addPersistentStoreWithType:NSSQLiteStoreType 
                                  configuration:nil 
                                            URL:[NSURL fileURLWithPath:iCloudData] 
                                        options:options 
                                          error:&error];
    
                if( error )
                {
                    NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);
    
                    // comment in this line while debugging if get "Can't find model for source store" error in addPersistentStoreWithType.
                    // it means the sqlite database doesn't match the new model and needs to be created from scratch.
                    // this happens if you change the xcdatamodel instead of creating a new one under Xcode->Editor->Add Model Version...
                    // CoreData can only automatically migrate if there is a new model version (it can't migrate if the model simply changes, because it can't see the difference between the two models).
                    // be sure to back up the database if needed, because all data will be lost.
                    //[fileManager removeItemAtPath:iCloudData error:&error];
    
                    /*// this is another way to verify the hashes for the database's model to make sure they match one of the entries in the momd directory's VersionInfo.plist
                    NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:[NSURL fileURLWithPath:iCloudData] error:&error];
    
                    if( !sourceMetadata )
                        NSLog(@"sourceMetadata is nil");
                    else
                        NSLog(@"sourceMetadata is %@", sourceMetadata);*/
                }
    
                [psc unlock];
            }
            else {
                NSLog(@"iCloud is NOT working - using a local store");
                NSMutableDictionary *options = [NSMutableDictionary dictionary];
                [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
                [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
    
                [psc lock];
            NSError *error;
    
                [psc addPersistentStoreWithType:NSSQLiteStoreType 
                                  configuration:nil 
                                            URL:localStore 
                                        options:options 
                                          error:nil];
    
            if( error )
                NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);    
                [psc unlock];
            }
    
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil];
            });
        });
    
        return __persistentStoreCoordinator;   
    }
    

    【讨论】:

    • 对于遇到此问题的其他人,请注意:您在 pathForResource 中提供的 momd 文件夹名称区分大小写!
    【解决方案3】:

    我也有同样的问题。我通过删除旧数据库并再次构建项目来解决它。我不确定这是不是正确的做法。显然它指向错误的数据库文件。就我而言,我正在使用核心数据创建一个简单的项目并尝试迁移。当我创建一个带有附加列的新模型并构建我​​的项目时,有 2 个文件 - coreData.sqlite 和 coreData ~.sqlite ... 所以我的感觉是,错误的数据库被指向,因此错误。当我删除数据库并再次构建项目时,它对我来说非常有效。

    如果您确实删除了数据库,最好将数据库的副本保存在另一个位置,以免丢失。

    【讨论】:

    • 最好的方法就是从手机中删除应用程序。下次启动模拟器重新安装应用时,它会生成一个新的sqlite数据库。
    【解决方案4】:

    错误消息意味着它找不到现有商店的.mom 编译模型文件。 Core Data 正在寻找配置存储的确切 .mom 版本。 .mom 文件告诉 Core Data 如何将文件中的序列化数据映射到对象中。如果没有该模型文件,它不知道如何将存储迁移到新模型,因为它不知道每个实体或实体属性都有哪些数据。

    我只见过一次,IIRC 的原因是新的.mom 文件与旧文件的名称和位置完全相同。更新应用程序时,旧的.mom 文件被覆盖。

    尝试更改新模型文件的名称,看看是否有帮助。如果没有,我们可能需要更多关于你在做什么的细节。

    【讨论】:

    • 对于遇到此问题的其他人,请注意:您在 pathForResource 中提供的 momd 文件夹名称区分大小写!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多