首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >+[NSManagedObjectModel mergedModelFromBundles::forStoreMetadata:]总是返回零

+[NSManagedObjectModel mergedModelFromBundles::forStoreMetadata:]总是返回零
EN

Stack Overflow用户
提问于 2019-04-06 02:44:10
回答 2查看 233关注 0票数 1

我有一个有15个版本的核心数据模型。它的代码可以在启动时逐步从当前商店的版本迁移到最新版本。

那的关键是打电话给

代码语言:javascript
复制
    NSDictionary* options = @{ NSMigratePersistentStoresAutomaticallyOption : @true,
                               NSInferMappingModelAutomaticallyOption : @true };
    NSDictionary* sourceMetadata = [NSPersistentStoreCoordinator
                                        metadataForPersistentStoreOfType: inType
                                        URL: inSourceStore
                                        options: options
                                        error: outError];
    NSManagedObjectModel* model = [NSManagedObjectModel mergedModelFromBundles: @[ [NSBundle bundleForClass: [self class]] ]
                                                        forStoreMetadata: inSourceMetadata];

但这一直是零,我不知道为什么。现有存储是版本14,新模型是版本15。

现在,对模型的最后一次更改相当琐碎(添加了两个可选字段),所以我认为它可以自动推断映射,但这不起作用,所以我使用Xcode的助手添加了一个从14版到15版的映射模型,没有做任何更改。

你知不知道它为什么要归零,或者我能做些什么来进一步调查?

同样,当我说“版本14”时,我指的是.xcdatamodel文件的顺序编号。有没有办法查看实际存储并确定模型Core数据的哪个版本认为它是?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-06 05:33:08

阿。结果,我编辑了最新的模型版本,而不是添加一个新的版本。所以没人能比得上。一旦我恢复了最新的版本,并添加了一个新的模型版本的变化,它运行良好,即使没有默认的映射模型。

我通过测试每个模型以确定它是否与源元数据匹配,我发现了这一点,使用以下方法:

代码语言:javascript
复制
    NSDictionary* storeHashes = [sourceMetadata objectForKey: NSStoreModelVersionHashesKey];
    NSArray<NSURL*>* urls = [self getModelURLs];
    urls = [urls sortedArrayUsingComparator:
                    ^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2)
                    {
                            NSURL* s2 = obj1;
                            NSURL* s1 = obj2;
                            return [s1.lastPathComponent compare: s2.lastPathComponent options: NSNumericSearch];
                    }];

    for (NSURL* url in urls)
    {
        NSDictionary* modelHashes = [self getHashesForModelAtURL: url];

        //  Compare the hashes…

        bool matches = true;
        for (NSString* entityKey in storeHashes.allKeys)
        {
            NSString* storeHash = storeHashes[entityKey];
            NSString* modelHash = modelHashes[entityKey];
            if (![storeHash isEqual: modelHash])
            {
                NSLogDebug(@"Model %@ has mismatch on %@", url.lastPathComponent, entityKey);
                matches = false;
            }
        }

        if (matches)
        {
            NSLogDebug(@"Version matches: %@", url.lastPathComponent);
            break;
        }
    }

- (NSArray<NSURL*>*)
getModelURLs
{
    NSBundle* bundle = [NSBundle bundleForClass: [self class]];
    NSArray<NSURL*>* urls = [bundle URLsForResourcesWithExtension: @"mom" subdirectory: @"Model.momd"];
    return urls;
}

- (NSDictionary*)
getHashesForModelAtURL: (NSURL*) inURL
{
    NSManagedObjectModel* model = [[NSManagedObjectModel alloc] initWithContentsOfURL: inURL];
    NSDictionary* hashes = model.entityVersionHashesByName;
    return hashes;
}
票数 0
EN

Stack Overflow用户

发布于 2019-04-06 06:01:11

首先,你似乎知道自己在做什么,通过14个核心数据迁移而幸存下来。所以我觉得你应该注意一些愚蠢的拍打前额的错误。

确保[NSBundle bundleForClass: [self class]]正在返回预期的包,其中包含一个目录Contents/Resources/YourModelName.momd,并且该目录包含所有所需的.mom文件(每个版本一个)和一个VersionInfo.plist文件。我的构建还包含一个仅适用于最新版本的.omo文件。

现在我将回答你的第二个问题,这确实可以帮助你回答你的第一个问题。

在这个VersionInfo.plist文件中,您将找到一个名为NSManagedObjectModel_VersionHashes的字典,它反过来包含子词典,每个版本都有一个键。每个版本的子字典包含每个实体名称和值的键,这是该版本中该实体的属性和关系的32字节(256位)散列。让我们把这叫做模型哈希。

现在使用SQLite查看器或sqlite3命令行工具打开存储数据库文件。在该数据库中,在模型中每个实体的一个表旁边,您将看到一个名为Z_METADATA的表,其中包含一行和三列。名为Z_PLIST的列的值被键入为二进制数据的blob。将该数据复制到文件中,将其命名为扩展名.plist、doubleclick,并在您最喜欢的plist编辑器中打开它,因为该数据实际上是一串以XML格式表示苹果属性列表的文本。它的键NSStoreModelVersionHashes的值实际上是一个子字典,它就像VersionInfo.plist文件中的子字典一样。我们把这叫做商店哈希吧。32字节(256位)版本哈希是Base64编码的.(有44个Base64字符。因为每个Base64字符代表6位,所以44个字符最多可以代表44*6 = 264位)。

最后,要回答您的第二个问题,传递给+[NSManagedObjectModel mergedModelFromBundles:forStoreMetadata:]+[NSManagedObjectModel mergedModelFromBundles:forStoreMetadata:]实际上是商店中的Z_METADATA,其中包含这些存储散列。+[NSManagedObjectModel mergedModelFromBundles:forStoreMetadata:]将这些存储散列与传入的bundle中每个候选数据模型中的模型哈希进行比较,并返回模型哈希与所有实体的存储哈希匹配的模型,其中两侧没有额外的不匹配实体。

所以你看手工做比较有点乏味。但是当你在这些褶皱中探索的时候,你可能会发现你的前额被猛击过。如果不是的话,给我们提供更多关于你粘贴的代码的上下文,也许有人能帮上忙。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55545388

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档