在 NSPersistentDocument 上启用核心数据的自动轻量级迁移
ALM 很棒。但我无法让它在使用 Core Data 和 NSDocument 的项目上工作。看来 ALM 默认是禁用的。
美好的。对于任何正常的项目,您都可以在这一行中将两个适当的选项添加到字典中:
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
...但是当将 CD 与 NSD 一起使用时,该行不存在(NSPersistentDocument 隐藏了详细信息,我看不到如何修改他们)。
下面的方法似乎带来了希望:
configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:
...邮件列表上的一些人(4 多年前)报告成功覆盖该方法,更改选项字典,然后在“super”上重新调用它。可悲的是,这对我不起作用。如果您遇到类似问题,我建议您先尝试一下 - 如果仍然不起作用,请回到这里:)
ALM is great. But I can't get it to work on a project that uses Core Data with NSDocument. It seems that ALM is disabled by default.
Fine. For any normal project, you'd add the two appropriate options to the dictionary in this line:
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
...but that line doesn't exist when using CD with NSD (NSPersistentDocument hides the details and I can't see how you can modify them).
The following method seems to offer hope:
configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:
...some people on mailing lists (from 4+ years ago) report success overriding that method, altering the options dictionary, and then re-invoking it on "super". That didn't work for me, sadly. I would advise trying that first if you have similar problems - then come back here if it still doesn't work :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
从头开始创建一个新的 Cored-Data-with-NSDocument 项目,我尝试了最初不起作用的方法,这次效果很好:
Making a new Cored-Data-with-NSDocument project from scratch, I tried the approach that didn't work originally, and it worked fine this time:
注意:我怀疑问题的根本原因是 Xcode4 错误更新它使用的私有哈希值,而不是版本号来跟踪数据模型版本。可能我不小心添加了一些东西,然后删除了它,它改变了哈希值 - 我原来的模型非常简单,很容易通过肉眼进行比较,并且没有任何差异。
另外,更一般地说,问题是 Xcode4 仍然 无法正确处理 CoreData 项目 - 它默认创建“版本化”的 CoreData 模型(相对于 Xcode3 来说有很大改进,Xcode3 注定总是创建无用的模型),但它仍然不会对模型中的更改进行任何处理 - 您必须在保存任何更改之前手动记住更新版本(否则您的所有项目迁移将永远失败,并显示没有出路)。
另外,一旦出现问题,我就找不到任何“正确”的解决方案——苹果的核心数据库中缺少太多的部分。基本上:据我所知,NSPersistentDocument 不完整,不受支持。
最后,我采用了以下残酷的解决方法:指示每个使用旧版本的人手动编辑 CoreData 存储以声明他们正在运行当前版本。
这 100% 有效,因为与 CoreData 不同,我的应用程序是为了智能地纠正导入时任何明显丢失的数据而编写的。这很简单,但是 CoreData 不允许您说“是的,我已经完成了这个。没关系。继续打开文件!”
...并且因为我重写了 NSManagedObject 方法:
-awakeFromInsert
并修复任何不正确/丢失的数据,所以上面的步骤 3 和 4 会“自动”更新数据。
我知道“正确”的方法是创建一个映射模型,但对于大多数情况来说,这是巨大的杀伤力……而且苹果一开始就拒绝加载旧数据。因此,核心数据甚至拒绝允许我更正数据——尽管我的代码很乐意这样做。
(所有旧项目都已正确导入和导出 - 没有问题)
恕我直言:CoreData 确实需要 Apple 端进行一些重新设计,以修复他们第一次没有考虑到的所有边缘情况。
注意:快速警告:确保不要更改 awakeFromFetch 中的任何 CoreData 变量 - Apple 在调用该方法之前暂时禁用更改跟踪(这有点可笑 - 它使该方法与所有其他“awakeFrom*”的行为不兼容方法)。
Apple 的建议:在 awakeFromFetch 中,决定要更改的内容,然后将其打包并使用如下所示的内容:
[self PerformSelector:@selector(myAwakeFromFetchFixItemX:) withObject:X afterDelay:0.01];
...只是想我会为尝试此操作的任何人添加这一点 - 否则您的导入将正常工作,但您的导出将默默地无法包含固定数据!
NB: I suspect the root cause of my problems is that Xcode4 is incorrectly updating the private hashes it uses instead of version numbers to track a data-model version. Probably I accidentally added something, then deleted it, and it changed the hash - my original model was so very simple it was easy to compare by eye, and there were no differences.
Also, more generally, the problem is that Xcode4 still doesn't handle CoreData projects properly - it creates CoreData models as "versioned" by default (big improvement from Xcode3, which was doomed to always create useless models), but it still doesn't do any handling of changes in the model - you must manually remember to update the version BEFORE you save any changes (or else all your project migration will fail, forever, with no way out).
Also, I couldn't find any "correct" solution once things go wrong - just too many missing pieces from Apple's Core Data lib. Basically: NSPersistentDocument is incomplete, unsupported, so far as I can tell.
In the end, I went with the following BRUTAL workaround: instructed everyone with old versions to manually edit the CoreData stores to claim they are running the current version.
This works 100%, because unlike CoreData, my app is written to intelligently correct any obvious missing data on import. It's trivial, but CoreData doesn't allow you to say "yes, I've done this. It's OK. Go ahead and open the file!"
...and because I'm overriding the NSManagedObject method:
-awakeFromInsert
and fixing any incorrect/missing data, the steps 3 and 4 above "automagically" update the data.
I know that the "correct" way would have been to create a mapping model, but it's massive overkill for most situations ... and Apple was refusing to load the old data in the first place. So, Core Data was just refusing to even allow me to correct the data - even though my code was happily doing so.
(all old projects have imported and exported correctly - no problems)
IMHO: CoreData really needs some re-design on Apple's end to fix all the edge-cases they didn't think about first time around.
NB: quick warning: make sure you DON'T change any CoreData variables inside awakeFromFetch - Apple temporarily disables change-tracking before calling that method (which is kind of laughable - it makes the method incompatible with the behaviour of all other "awakeFrom*" methods).
Apple's advice: inside awakeFromFetch, decide what you're going to change, then package it up and use something like this:
[self performSelector:@selector(myAwakeFromFetchFixItemX:) withObject:X afterDelay:0.01];
...just thought I'd add that for anyone trying this - otherwise your import will work fine, but your export will silently fail to include the fixed data!