iPhone核心数据轻量级迁移Cocoa错误134130:找不到源存储的模型

时间:2010-06-30 04:41:18

标签: iphone core-data

民间,

轻量级迁移在这条线路上100%的时间都失败了:

[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]

错误:

Error: Error Domain=NSCocoaErrorDomain Code=134130 UserInfo=0x4fbff20 "Operation could not be completed. (Cocoa error 134130.)"
"Can't find model for source store";

这是我的托管对象上下文,模型和持久性存储:

- (NSManagedObjectContext *) managedObjectContext {

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

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }
    return managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel {

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

    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
    return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Locations.sqlite"]];

    NSError *error;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

    // Allow inferred migration from the original version of the application.
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
        NSLog(@"Error: %@",error);
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator;
}

我的项目中有两个版本的模型:版本4和版本5.如果我将版本4设置为默认值,它可以正常工作。如果我选择“设计 - >数据模型 - >添加模型版本”(如this post所述),请进行更改,设计 - >数据模型 - >设置当前版本,构建和运行,它将失败,前面提到“无法找到源存储模型”错误。将模型设置回版本4,没有问题,addPersistentStoreWithType。或者,如果我添加模型版本并且不做任何更改,只需从版本4转到5而不添加任何新字段,没有问题。如果我然后尝试从5到6,上述错误。

此代码在模拟器和手机上都失败了。我阅读了几个要求删除和重新安装应用程序的处方,这对于模拟器和手机都有效,但我担心当我向真实用户发布时,它会破坏我的安装基础,因为它们将无法删除并重新安装 - App Store将自动升级它们。

此代码在过去的版本中有效,我没有任何变化 - 因此我能够将其一直升级到版本4.我最近升级到iOS4的XCode 3.2.3版本,这可能与此有关。

其他人是否像我一样突然出现这个问题?有没有人设法超越它?感谢。

PS - 对于偶然发现此页面的Google员工,以下是您可能会考虑阅读的所有相关页面。不幸的是,这些都没有解决我的问题。

更新

虽然这不是一个真正的修复,但它确实避免了崩溃客户端的情况:只需删除数据库文件:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {



    // Delete file
    if ([[NSFileManager defaultManager] fileExistsAtPath:storeUrl.path]) {
        if (![[NSFileManager defaultManager] removeItemAtPath:storeUrl.path error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) 
    {
        // Handle the error.
        NSLog(@"Error: %@",error);
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();

    }
}    

更新2

以下是我检查VersionInfo.plist时发生的情况:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>NSManagedObjectModel_CurrentVersionName</key>
        <string>Profile 5</string>
        <key>NSManagedObjectModel_VersionHashes</key>
        <dict>
                <key>Profile</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        ZIICGgMBreuldkPXgXUhJwKamgwJzESM5FRTOUskomw=
                        </data>
                </dict>
                <key>Profile 2</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        tEB7HrETWOSUuoeDonJKLXzsxixv8ALHOoASQDUIZMA=
                        </data>
                </dict>
                <key>Profile 3</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        qyXOJyKkfQ8hdt9gcdFs7SxKmZ1JYrsXvKbtFQTTna8=
                        </data>
                </dict>
                <key>Profile 4</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        lyWDJJ0kGcs/pUOModd3Q1ymDvdRiNXui4NCpLxDFSw=
                        </data>
                </dict>
                <key>Profile 5</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        V4PyRK1ezj3xK1QFRCTVzGOqyJhEb7FRMzglrTsP0cI=
                        </data>
                </dict>
        </dict>
</dict>
</plist>

这是我编写的用于检查模型的代码(注意我必须出去添加一个base64编码器,因为这是VersionInfo.plist文件中的内容)

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {


    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeUrl error:&error];
    NSLog(@"%@",storeMeta);
    id someObj = [[storeMeta objectForKey:@"NSStoreModelVersionHashes"] objectForKey:@"Profile"];
    NSLog(@"%@",someObj);
    NSLog(@"%@",[NSString base64StringFromData:someObj length:[someObj length]]);

这是调试输出:

{
    NSPersistenceFrameworkVersion = 310;
    NSStoreModelVersionHashes =     {
        Profile = <97258324 9d2419cb 3fa5438c a1d77743 5ca60ef7 5188d5ee 8b8342a4 bc43152c>;
        SerializedMessage = <4530863c d943479a edfb4dfb 5059c28d d6137dc4 d1153d36 ed52be49 11074f13>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
    );
    NSStoreType = SQLite;
    NSStoreUUID = "823FD306-696F-4A0F-8311-2792825DC66E";
    "_NSAutoVacuumLevel" = 2;
}

<97258324 9d2419cb 3fa5438c a1d77743 5ca60ef7 5188d5ee 8b8342a4 bc43152c>
lyWDJJ0kGcs/pUOModd3Q1ymDvdRiNXui4NCpLxDFSw=

正如您所看到的,以'ly'开头的最后一行与VersionInfo.plist中的Profile 4相匹配......因此我认为没有理由说它应该失败。还有其他想法吗?

5 个答案:

答案 0 :(得分:9)

  

我读了几个叫处方   删除并重新安装应用程序,   哪个适用于模拟器和   电话,但我害怕当我   将它发布给真正的用户   打破我的安装基础,因为他们   将无法删除并重新安装。

这是一个问题,当Xcode没有从模拟器/ dev-device中移除旧的momc文件时,如果模型文件被更改,例如改名称。旧文件仍然会导致混淆。这是你在开发过程中只看到的东西,因为它是Xcode操纵应用程序包的方式的工件,而不是每次完全重新安装它,就像发布版本必须发生的那样。

您可以确认此记录返回:

[[NSBundle mainBundle] URLsForResourcesWithExtension:@"momc"subdirectory:nil];

...它应该显示应用程序包中所有已编译的模型文件

在开发过程中依赖迁移是不好的做法,因为如果要对模型和存储进行更改,迁移很常见。所有代码都被固定后,您应该只使用迁移。我还建议您每次运行时从头开始重新生成商店。通过更改模型很容易在商店中建立垃圾。

答案 1 :(得分:4)

我已阅读您更新的问题。模型版本变得非常混乱。

您应该尝试审核现有商店实际要求的模型版本,并尝试在运行时列出应用包中的所有可用模型。


我查看我的应用程序的模型目录

NSString *modelDirectoryPath = [[NSBundle mainBundle] pathForResource:@"MyModel" ofType:@"momd"];

我不确定开发人员是否通常这样做,但我保留了不同名称的模型版本..所以我在那里:

  • VersionInfo.plist
  • MyModel.mom
  • MyModel2.mom

VersionInfo.plist中列出的版本哈希应该可以帮助您排除故障。查找现有持久性存储所需的版本哈希,看看是否可以在VersionInfo.plist中列出的版本哈希中找到它。

实际上,我找不到一种方法来编写一些代码,这些代码会向持久性存储区询问它的实体版本哈希是什么。 NSPersistentStoreCoordinatorNSMigrationManger似乎是私下做的。即,他们根据加载商店的模型检查持久性商店实体版本。


还有另一个快速查看,它可以在商店元数据中找到。很好,很容易!

NSError *error;
NSURL *storeURL = [NSURL fileURLWithPath:[[self class] storePath]];
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeURL error:&error];

storeMeta中查看

的密钥
<CFString 0x7328050 [0x2724380]>{contents = "NSStoreModelVersionHashes"} = <CFBasicHash 0x7328340 [0x2724380]>{type = immutable dict, count = 5,
entries =>
    0 : <CFString 0x7328110 [0x2724380]>{contents = "MyEntityNameOne"} = <CFData 0x73281b0 [0x2724380]>{length = 32, capacity = 32, bytes = 0x143325cf121239ce156af2e2a1aad7d9 ... 976977fdf29fc013}
    1 : <CFString 0x7328130 [0x2724380]>{contents = "MyEntityNameTwo"} = <CFData 0x7328200 [0x2724380]>{length = 32, capacity = 32, bytes = 0x0ca6ecf1283d12bd3ca82af39b6b9f5d ... 149dd39a591e0c4d}
    ...    }

应该很容易迭代NSStoreModelVersionHashes字典,并记录商店所需的版本哈希值。

将其与VersionInfo.plist中的可用内容进行手动匹配,然后查看缺少的内容。也许没有一个模型包含现有持久性存储中所有实体所需的版本。这可能是由于在设置新模型版本之前或之后模型上的(偶然?)编辑而发生的?

答案 2 :(得分:4)

我遇到了esilver的确切问题,并通过Google发现了这个问题。但是,对我有用的修复工具并不是SO上的任何其他东西(我知道),所以这里有:

如果您的捆绑包中有*.mom个文件(编译对象模型)的多个副本,则在尝试代表您迁移时,Core Data可能会感到困惑。

我们的问题是,每个单独的模型文件(Data.xcdatamodelData_V1.xcdatamodelData_V2.xcdatamodel等)不仅位于xcdatamodeld/目录中(包含在内容中)在构建过程中编译),但每个文件也包含在“编译源”列表中。

这意味着生成的包有两组*.mom个文件:一个在xcdatamodeld/内,一个在顶层。我认为Core Data变得非常非常困惑,并导致了这个错误。从“编译源”中删除每个xcdatamodel文件并离开xcdatamodeld目录解决了我们的问题(例如,自动版本升级并再次运行)。希望这有帮助!

答案 3 :(得分:0)

在我的情况下,完全相同的事情正在发生,我在iOS 7上,这个问题至少让我头脑干了一个星期,然后终于找到适合我的解决方案 。 为了使它工作,你必须在用于添加PersistentStore的选项中添加额外的值,然后你去(我不确定其他iOS版本,但是它肯定会在iOS 7上运行)。

-(NSManagedObjectModel *)managedObjectModel
{
    if (managedObjectModel != nil)
    {
        return managedObjectModel;
    }
    managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    return managedObjectModel;
}

-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
 {

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

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"ABC.sqlite"];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] ini   tWithManagedObjectModel:[self managedObjectModel]];

//Creating Lightweight migration.
    NSDictionary *options =
    @{
      NSMigratePersistentStoresAutomaticallyOption:@YES
      ,NSInferMappingModelAutomaticallyOption:@YES
      ,NSSQLitePragmasOption: @{@"journal_mode": @"DELETE"}
     };


   if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
    {
       NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
       abort();
    }
return persistentStoreCoordinator;
}

答案 4 :(得分:-2)

民间,

为了记录,我完全停止使用核心数据。我的代码很复杂,并且根据上述问题,不可靠。我现在直接使用SQLLite,我很高兴。我不建议在任何情况下使用Core Data。