iOS 12的具体问题:核心数据外部存储二进制数据损坏

zen*_*ndo 27 core-data ios swift ios12

我花了很多时间试图解决这个问题.

背景

我有一个简单的核心数据模型,有书籍和阅读课程.这些书的封面(图像)以"允许外部存储"存储为二进制数据.

在iOS 11.4及更低版本中,一切都运行良好.当我保存新会话时,所有内容都会正确更新.

问题

由于iOS的12,当我创建一个新的阅读会话并将其链接到这本书,大约每的时间,核心数据生成SQL语句也更新图书封面领域,有时会造成不好的引用(到磁盘上的文件),它通常会在重新启动应用程序时导致封面为零,并且几乎总是在磁盘上创建封面的副本(如模拟器的_EXTERNAL_DATA文件夹中所示).

内存上下文和对象保持正确(因此UI中的所有内容都可以),直到应用程序重新启动,然后封面通常为零.

iOS 12具体

在iOS 12上,我可以确定地在物理设备上重现模拟器中的错误,并且用户也报告了错误.我无法在iOS 11.4上重现错误,也没有用户报告iOS 12之前的错误.

采取的步骤

  • 我启用了" -com.apple.CoreData.ConcurrencyDebug 1",所以不应该是我从错误的队列中访问任何东西.我也启用了" -com.apple.CoreData.SQLDebug 3",以便我可以确切地看到写入的内容.

  • 我做了保证书的情况下(因此盖)通过我的代码以通过检查新会联想之前没有修改hasChanges,只是我之前做newSession.book = bookcontext.save().

  • 为了100%肯定我没有触及任何线程上的封面属性我已经将我的getter和setter用于该属性的短路.没有得到改善.

  • 我已经尝试objectID过在关联之前请求一本书的实例并保存.没有得到改善.

  • 我甚至尝试了上下文保持对所有对象的强引用的选项,只是为了确保它不是某种内存管理问题.没有得到改善.

下一步的任何想法?

状态更新

这是iOS 12中的一个缺陷.请参阅下面接受的答案,了解有关合理解决方法的详细说明.

rod*_*han 9

更新:基础核心数据问题似乎已在iOS 12.1中得到解决(在测试版4中得到验证).我们将在我们的应用程序中保留下面描述的解决方法,并且不会建议您尽快使用外部存储选项.


在与Apple工程师交谈并提交上述雷达之后,我们无法等待修复,因此我们采取了命中并切换到将文件存储在文件系统上并直接自行管理.

我们考虑的另一个替代方案是迁移我们的模型,不允许外部存储用于BLOB,但我不知道会对性能产生什么影响,我也担心在这部分iOS看起来模型迁移的时候不稳定,特别是在阅读过去这样的故事之后:核心数据:不要将大型文件存储为二进制数据 - Alexander Edge - Medium

自己实施本地存储并不是太痛苦.您只需要为每条记录创建一个唯一标识符,您可以使用该标识符创建文件名,以便将文件映射到记录.我们为Managed Object子类添加了一个扩展,其中包含读取,写入和删除文件的方法.现在,article.photo = image.pngData()我们现在需要调用类似的东西article.savePhoto(image.pngData()),然后在我们想要检索图像时执行相似的操作,而不是调用eg .您还可以向这些方法添加一些代码,以支持向后兼容当前存储在Core Data中的任何图像.

删除有点棘手,因为我们的对象从代码中的多个位置删除,包括级联删除.最后,我选择在托管对象的prepareForDeletion方法中执行此操作,但这并不理想.这里有很多关于如何最好地实现它的讨论:cocoa - 如何在删除未保存的 Core Data对象时处理外部数据的清理?- 堆栈溢出

最后,为了防止我的应用程序在非可选二进制属性因此错误而消失时崩溃,我awakeFromFetch在我的Managed Object子类中重写以确保所有必需属性都不为nil,如果是,我将它们设置为占位符图像这样它们就可以在没有验证失败的情况下保存.

  • 此核心数据问题现在似乎已在iOS 12.1 beta 4中得到修复. (2认同)