用于开设商店的模型与用于创建商店的模型不兼容


181

我在xcode 3.2中创建了一个核心数据模型,并在Xcode 4.2中进行了升级,然后添加了NSManagedObject子类的新实体(请参阅新实体)。

首先,它看起来很奇怪,因为它与旧的不在同一个组中。这是我的xcode 4.2上的图片(AlkitabDB是我在xcode 3.2中创建的图片,EndeDB是当前xcode版本(4.2)中的新图片:

新实体未在xdatamodel中分组

第二件事,让它保持原样,然后我以与第一个实体(旧的)相同的方式访问第二个实体(新的),并出现标题为错误的错误。

这是错误:

2012-01-16 21:13:38.496 iHuria[55953:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)" UserInfo=0x8829cd0 {metadata=<CFBasicHash 0x882a370 [0x1839b38]>{type = immutable dict, count = 7,
entries =>
    2 : <CFString 0x8829b90 [0x1839b38]>{contents = "NSStoreModelVersionIdentifiers"} = <CFArray 0x8829ff0 [0x1839b38]>{type = immutable, count = 0, values = ()}
    4 : <CFString 0x8829bc0 [0x1839b38]>{contents = "NSPersistenceFrameworkVersion"} = <CFNumber 0x8829770 [0x1839b38]>{value = +320, type = kCFNumberSInt64Type}
    6 : <CFString 0x8829bf0 [0x1839b38]>{contents = "NSStoreModelVersionHashes"} = <CFBasicHash 0x882a080 [0x1839b38]>{type = immutable dict, count = 1,
entries =>
    0 : <CFString 0x882a010 [0x1839b38]>{contents = "AlkitabDB"} = <CFData 0x882a030 [0x1839b38]>{length = 32, capacity = 32, bytes = 0xd02ac5f8be6ab0b39add450aca202ac0 ... 3d45d462998d2ccd}
}

    7 : <CFString 0x10e3aa8 [0x1839b38]>{contents = "NSStoreUUID"} = <CFString 0x8829e60 [0x1839b38]>{contents = "4F2EE7FF-463B-4055-BBED-8E603CDBDF59"}
    8 : <CFString 0x10e3948 [0x1839b38]>{contents = "NSStoreType"} = <CFString 0x10e3958 [0x1839b38]>{contents = "SQLite"}
    9 : <CFString 0x8829c40 [0x1839b38]>{contents = "NSStoreModelVersionHashesVersion"} = <CFNumber 0x6b1c7c0 [0x1839b38]>{value = +3, type = kCFNumberSInt32Type}
    10 : <CFString 0x8829c70 [0x1839b38]>{contents = "_NSAutoVacuumLevel"} = <CFString 0x882a0c0 [0x1839b38]>{contents = "2"}
}
, reason=The model used to open the store is incompatible with the one used to create the store}, {
    metadata =     {
        NSPersistenceFrameworkVersion = 320;
        NSStoreModelVersionHashes =         {
            AlkitabDB = <d02ac5f8 be6ab0b3 9add450a ca202ac0 ebd1e860 cbb578c2 3d45d462 998d2ccd>;
        };
        NSStoreModelVersionHashesVersion = 3;
        NSStoreModelVersionIdentifiers =         (
        );
        NSStoreType = SQLite;
        NSStoreUUID = "4F2EE7FF-463B-4055-BBED-8E603CDBDF59";
        "_NSAutoVacuumLevel" = 2;
    };
    reason = "The model used to open the store is incompatible with the one used to create the store";
}

之前,我一直在寻找解决方案,发现我应该从模拟器中删除该应用程序,然后重新运行该应用程序,但该方法不起作用。有人知道这个问题的解决方案吗?请帮忙。

Answers:


294

有时情况并非如此!建议,您的应用已发布!您不能只是将新实体添加到数据库并继续进行-您需要执行迁移!

对于那些不想深入研究文档并正在寻找快速修复方法的人:

  1. 打开您的.xcdatamodeld文件
  2. 点击编辑器
  3. 选择添加模型版本...
  4. 添加模型的新版本(添加了新的一组数据模型)
  5. 选择主文件,打开文件检查器(右侧面板)
  6. 然后在Versioned core data model当前数据模型下选择新版本的数据模型
  7. 不仅如此),您应该执行所谓的“轻迁移”。
  8. 转到您的文件夹AppDelegate,找到persistentStoreCoordinator要创建的位置
  9. 找到这条线 if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
  10. nil选项替换为@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}(实际上在该方法的注释代码中提供)
  11. 给你,玩得开心!

PS这仅适用于轻量级迁移。为了使您的迁移符合轻量级迁移的要求,您的更改必须限于以下范围:

  • 添加或删除属性(属性或关系)。
  • 将非可选属性设为可选。
  • 只要您提供默认值,就使可选属性成为非可选。
  • 添加或删除实体。
  • 重命名属性。
  • 重命名实体。

对于Swift 4

coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])

2
主文件是您创建的.xcdatamodel。您应该打开“实用程序”窗格的第一个选项卡(右侧的一个)并找到“模型版本”(Xcode 5.1),然后选择“当前:”“您新创建的.xcdatamodel”
Stas

1
@ Computer_whiz123,在XCode 5.1.1中被称为“模型版本”
Stas

1
我要怎么做才是Swift?
Addison

2
我收到此错误:“ CoreData:错误:-addPersistentStoreWithType:SQLite配置:(空)URL:file:///...file.sqlite选项:{NSInferMappingModelAutomaticallyOption = 1; NSMigratePersistentStoresAutomaticallyOption = 1;} ...返回的错误错误Domain = NSCocoaErrorDomain代码= 134130“操作无法完成。(可可错误134130。)”
CarmenA,2015年

3
快速迁移选项:let options = [ NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption:true ]
Hamza

285

从模拟器中删除该应用程序,然后对项目进行清理。那应该清除那些问题。删除应用程序时,请确保您未在​​调试器中运行,否则它实际上不会正确删除。

如果您要确定它已消失,请Users/INSERT_YOUR_USER_HERE/Library/Application Support/iPhone Simulator/在您正在运行的版本下,在此目录中查找您应用程序的文件夹。

注意:这仅用于开发。对于生产,您需要实施某种迁移。Google“核心数据迁移”,最简单的轻量级迁移。


谢谢菲利普,我尝试了一下,但没有成功:(,你还有其他建议吗?
dejoong 2012年

您可以在应用程序委托中发布使用创建模型和持久性存储的代码吗?
菲利普·萨布林

这有点不合理,为什么会这样,为什么这样的解决方案可以解决问题,但这就是..无法帮助.. nywaz,这是我的投票。.我现在能做的最好的事情就是感谢您的指导..非常感谢为了帮助队友!!
Apple_iOS0304

帮助我解决了Xcode 4.6中的一个问题,在那里我误将所有项目文件发送到垃圾箱:/
ramirogm

6
这仅用于开发!对于生产,您可以使用模型版本控制和迁移。developer.apple.com/library/ios/#documentation/cocoa/Conceptual/...
菲利普·萨布林

35

只需在AppDelegate.m文件中为核心数据方法创建persistentStoreCoordinator时添加Options属性,如下所示

目标C

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil)
    {
        return _persistentStoreCoordinator;
    }

    NSLog(@"persistentStoreCoordinator___");
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];

    NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];

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

    NSLog(@"persistentStoreCoordinator___2");
    return _persistentStoreCoordinator;
}

迅速

    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
    // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
    var failureReason = "There was an error creating or loading the application's saved data."

    // MAIN LINE OF CODE TO ADD
    let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
                    NSInferMappingModelAutomaticallyOption: true]

    do {
        try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions)
    } catch {
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason

        dict[NSUnderlyingErrorKey] = error as NSError
        let wrappedError = NSError(domain: "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 \(wrappedError), \(wrappedError.userInfo)")
        abort()
    }

    return coordinator
}

它解决了我的问题。


1
谢谢你的这篇文章,它真的很有帮助
Subramani

23

答:从模拟器中删除该应用程序,执行清理并重新生成您的项目。

注意:每当您对核心数据定义进行更改时,请删除物理设备或模拟器上安装的应用程序,清理项目并重新构建。


重置模拟器中的内容和设置对我来说解决了这个问题!谢谢。
Septerr

14

是。在物理设备上删除应用并重新构建应用后,它便可以正常工作。


这实际上解决了我的问题,而不是接受的答案。谢谢!
肯W

生产中发生的事情不是答案
Eduardo Oliveros

这是一个可怕的答案,您需要向新模型中添加迁移,否则该应用将在生产时崩溃
aryaxt

14

要快速查找,请在AppDelegate.swift中找到该行

try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration:  nil, URL: url, options: nil )

并替换为

try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])

11

我花了几天时间解决此错误,以及mergedModelFromBundles崩溃以及出现“无法将模型与名为*的两个不同实体合并”错误。

事实证明,根本问题是Xcode不会从设备中删除旧资源,并且我的数据模型的旧版本(.mom文件)引起冲突。这就是为什么删除该应用程序可以解决我的设备之一上的问题的原因。

通过另一个SO答案找到此博客文章后,我通过更改查找所有.mom文件的这一行,使我的应用更能容忍旧模型:

NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];

只能在Filters目录中查找:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Filters" ofType:@"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];

我从以下问题中使用了recursivePathsForResourcesOfType:通过记录应用程序中的所有.mom文件来帮助解决这一问题

NSArray *momPaths = [self recursivePathsForResourcesOfType:@"mom" inDirectory:[[NSBundle mainBundle] resourcePath]];
NSLog(@"All .mom files:%@",momPaths);

我还使用iExplorer来查看无关的.mom文件(我尚未尝试删除它们)。

下面的方法也很有帮助。它表明实体在[pscmanagedObjectModel]返回的合并模型中,而该实体在我的任何模型或商店本身中都不存在。这就是让我相信旧模型正在缓存在设备上的原因,而干净的建筑并没有删除。该方法记录与模型相同,已更改,添加到模型或从模型删除的每个实体。(以该SO答案作为起点编写):

- (BOOL)comparePersistentStore:(NSPersistentStoreCoordinator *)psc withStoreURL: (NSURL *)storeURL {
    NSError *error = nil;

    // Get the entities & keys from the persistent store coordinator
    NSManagedObjectModel *pscModel = [psc managedObjectModel];
    NSDictionary *pscEntities = [pscModel entitiesByName];
    NSSet *pscKeys = [NSSet setWithArray:[pscEntities allKeys]];
    //NSLog(@"psc model:%@", pscModel);
    //NSLog(@"psc keys:%@", pscKeys);
    NSLog(@"psc contains %d entities", [pscModel.entities count]);

    // Get the entity hashes from the storeURL
    NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
                                                                                          URL:storeURL
                                                                                        error:&error];
    NSDictionary *storeHashes = [storeMetadata objectForKey:@"NSStoreModelVersionHashes"];
    //NSLog(@"store metadata:%@", sourceMetadata);
    NSLog(@"store URL:%@", storeURL);
    NSLog(@"store NSStoreUUID:%@", [storeMetadata objectForKey:@"NSStoreUUID"]);
    NSLog(@"store NSStoreType:%@", [storeMetadata objectForKey:@"NSStoreType"]);
    NSSet *storeKeys = [NSSet setWithArray:[storeHashes allKeys]];

    // Determine store entities that were added, removed, and in common (to/with psc)
    NSMutableSet *addedEntities = [NSMutableSet setWithSet:pscKeys];
    NSMutableSet *removedEntities = [NSMutableSet setWithSet:storeKeys];
    NSMutableSet *commonEntities = [NSMutableSet setWithSet:pscKeys];
    NSMutableSet *changedEntities = [NSMutableSet new];
    [addedEntities minusSet:storeKeys];
    [removedEntities minusSet:pscKeys];
    [commonEntities minusSet:removedEntities];
    [commonEntities minusSet:addedEntities];

    // Determine entities that have changed (with different hashes)
    [commonEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
        NSData *storeHash = [storeHashes objectForKey:key];
        NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
        if ( ! [pscDescrip.versionHash isEqualToData:storeHash]) {
            if (storeHash != nil && pscDescrip.versionHash != nil) {
                [changedEntities addObject:key];
            }
        }
    }];

    // Remove changed entities from common list
    [commonEntities minusSet:changedEntities];

    if ([commonEntities count] > 0) {
        NSLog(@"Common entities:");
        [commonEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
            NSData *storeHash = [storeHashes objectForKey:key];
            NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
            NSLog(@"\t%@:\t%@", key, pscDescrip.versionHash);
        }];
    }
    if ([changedEntities count] > 0) {
        NSLog(@"Changed entities:");
        [changedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
            NSData *storeHash = [storeHashes objectForKey:key];
            NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
            NSLog(@"\tpsc   %@:\t%@", key, pscDescrip.versionHash);
            NSLog(@"\tstore %@:\t%@", key, storeHash);
    }];
    }
    if ([addedEntities count] > 0) {
        NSLog(@"Added entities to psc model (not in store):");
        [addedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
            NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
            NSLog(@"\t%@:\t%@", key, pscDescrip.versionHash);
        }];
    }
    if ([removedEntities count] > 0) {
        NSLog(@"Removed entities from psc model (exist in store):");
        [removedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
            NSData *storeHash = [storeHashes objectForKey:key];
            NSLog(@"\t%@:\t%@", key, storeHash);
        }];
    }

    BOOL pscCompatibile = [pscModel isConfiguration:nil     compatibleWithStoreMetadata:storeMetadata];
    NSLog(@"Migration needed? %@", pscCompatibile?@"no":@"yes");

    return pscCompatibile;
}

用法:在将每个存储添加到NSPersistentStoreCoordinator之前调用:

    [self comparePersistentStore:self.psc withStoreURL:self.iCloudStoreURL];
    _iCloudStore = [self.psc addPersistentStoreWithType:NSSQLiteStoreType
                                          configuration:nil
                                                    URL:self.iCloudStoreURL
                                                options:options
                                                  error:&localError];

10

每次更改“核心日期”定义时,都应删除物理设备或模拟器上安装的应用程序。


20
生产应用程序呢?如果您将对Core Data的更改推送到App Store进行更新,它们会立即崩溃吗?Thx
rwyland 2013年


3
是的,CD模型的更改会阻止加载使用先前模型生成的数据。要解决此问题,您需要检测到问题并进行核心数据迁移。
约翰·


7

在Swift 2.1中对我有用的最简单的解决方案是Xcode 7:

  1. 从模拟器中删除应用程序(按Cmd + Shift + H进入主屏幕。长按应用程序,单击十字,这是从手机中删除应用程序的通常方法)

  2. 再按一次Cmd + Shift + H键可停止应用程序跳舞

  3. 返回您的项目并重新运行

在设置2个实体的情况下从Core Data读写数据时遇到了这个问题。删除应用程序并重新运行程序可解决此问题


2
生产中的不良做法,导致应用程序崩溃
Eduardo Oliveros

6

[Simulator App Folder]/Document/*.sqlite在实体中进行更改后,我只是删除了文件,它可以正常工作。当然,.sqlite文件包含所有丢失的数据和结构。


2
也为我工作。这应该足够了,这似乎是合理的。您虽然已经
删除

6

请从模拟器中删除应用程序并清除代码,然后运行。它可以正常工作。可能对您有帮助。


6

如果您使用的是Swift。

按照@Stas的回答进行操作,并在应用程序委托中插入选项(代替nil):

let myOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
            NSInferMappingModelAutomaticallyOption: true]
        if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: myOptions, error: &error) == nil {

1
不知道为什么投票否决了,但是我纠正了。感谢您提供Swift的语法。
马特·朗

真好!这行得通!谢谢!我试图解决这个问题3个小时。
mr_ivan777

这段代码放在哪里?我加载核心数据与此代码让容器= NSPersistentContainer(名: “modeldb”)container.loadPersistentStores(completionHandler:{(storeDescription,误差)要是让误差=误差作为NSError {?
MAS约翰。

5

在模拟器中尝试“重置内容和设置”。在删除应用程序并清理构建后为我工作


3
但是,如果执行此操作,那么在真实计算机上的用户是否还会出现相同的问题?
Maury Markowitz 2014年

4

我的应用程序遇到了同样的问题(尚未在App Store中发布)。

这是我解决的方法:

  1. 运行清理(Cmd + Shift + K)
  2. 重新启动iOS模拟器
  3. iOS模拟器->重置内容和设置(来自导航栏)

(3)是最终使其正常运行的步骤。希望这可以帮助!


2

尽管有时您可以在更改托管对象模型中的架构时仅从设备中删除该应用程序,但是在某些情况下这是不可能的,例如,因为您已经使用旧架构发布了该应用程序。

在这种情况下,您必须注意将旧数据迁移到新架构:

核心数据模型版本控制和数据迁移



2

如果您对核心数据模型进行更改,则必须提供一个迁移策略,该策略告诉核心数据如何将现有的持久化对象(您的用户使用当前发布的版本创建)采纳到新模型中。

在某些情况下,Core Data能够自动推断从旧模型到新模型的映射。对于更复杂的更改,您可能必须实现一些执行迁移的逻辑。

有关详细信息,请参见《核心数据模型版本控制和数据迁移编程指南》

更新
此处有关Stack Overflow的答案涵盖了Core Data轻量级迁移的基础,并且还提供了一些入门代码。


这里是我的回答对同一数据迁移:stackoverflow.com/questions/8881453/...
Dhaval H.尼纳

1

通常由于创建数据库的版本之间不兼容而发生此问题。解决此问题的一般方法是删除应用程序并重新安装。但是在您提到的情况下,Xcode 3.2和4.2上的数据库版本完全不同。因此最好使用相同版本的Xcode for DB。


1

首先,xcdatamodeld捆绑包中唯一应包含的内容是xcdatamodel文件。您的子类应该处于xcdatamodeld。将它们移到那里。他们有很大的机会混淆编译器。

其次,该错误表明Core Data无法找到您的模型。您是否创建了数据然后触摸了模型?如果是这样,则您处于不一致状态,需要通过删除数据(Philippe建议)或滚动对BACK的更改来解决此问题。


您是否知道如何从xcdatamodel捆绑包中取出模型?还是我只是删除它?
dejoong 2012年

该模型即xcdatamodel文件位于其中。.h和.m文件需要移动。使用查找器。
Marcus S. Zarra 2012年

0

我收到错误,但是收到错误的原因是由于以下原因。

我最初有一个名为“ Entry”的实体,并在数据库中为该实体保存了一行。然后,我添加了另一个名为“ Person”的实体,添加后去构建并得到了错误。因此,我通过删除“人员”实体,然后构建应用程序,删除了“条目”中的行,然后关闭了应用程序,解决了该问题。然后,我从手机上完全删除了该应用程序,然后进行了重建,效果很好。不知道哪一步可以解决问题(删除行或应用程序),但是希望如果您正在寻找解决方案,将对您有所帮助。:)

编辑:哦,如果您担心要删除新实体(在我的情况下为“ Person”)来再次构建应用程序,请记住,之后可以使用CMD + Z将其取回!


0

我遇到了这个问题-我先重置模拟器,然后清理项目并重建。然后工作。


0

当您更改核心数据(向表中添加字段,删除字段等)时,应用程序文档文件夹中的sqlite文件需要与您的架构同步。

默认情况下不会覆盖此文件,需要重新生成此文件。

跟着这些步骤:

  1. 转到NSURL指向的文件夹。(此路径可以在崩溃之前由应用程序生成的异常消息中找到。)示例:/ Users // Library / Application Support / iPhone Simulator // Applications // Documents

  2. 删除或重命名sqlite文件

  3. 清理并重新运行应用程序
  4. 正在运行的应用程序将生成一个新的sqlite文件。

这将确保架构和Xcode同步。


-1

对于Mac应用程序开发:

  1. 清理项目
  2. 清理派生数据
  3. 转到/ Users / YOUR_NAME / Library / Containers / YOUR_APP_BUNDLE_ID / Data / Documents /并删除其中的所有文件(例如“ .sqlite”,“。sqlite-shm” ...)

它为我工作,希望这会有所帮助。


-2

iOS模拟器->重置内容和设置...

为我工作

iOS模拟器->重置内容和设置...->重置也适用于iOS9(xcode 7.1)


4
生产中的不良做法,导致应用程序崩溃
Eduardo Oliveros
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.