当前位置: 首页 > 面试题库 >

iOS 12特定问题:核心数据外部存储二进制数据损坏

高森
2023-03-14
问题内容

我花了工作日的大部分时间来解决这个问题。

背景

我有一个简单的核心数据模型,包括书籍和阅读课程。这些书的封面(图像)以二进制数据形式存储在“允许外部存储”中。

在iOS 11.4及更低版本上,所有时间都可以正常运行。当我保存一个新会话时,所有内容都会正确更新。

问题

从iOS 12开始,当我创建一个新的阅读会话并将其链接到书时,核心数据大约每隔 2秒钟
生成一条SQL语句,该语句也会更新书的封面字段,有时会导致错误引用(对磁盘上的文件的引用)重新启动应用程序时,通常会导致封面 无效
,并且几乎总是在磁盘上创建封面的重复副本(可以在Simulator的_EXTERNAL_DATA文件夹中看到)。

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

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%确定我没有触及任何线程上的cover属性,我已将该属性的吸气剂和吸气剂短路了。没提升。

  • 我尝试objectID过在关联并保存之前请求该书的实例。没提升。

  • 我什至尝试了使用上下文对所有对象保持强引用的选项,以确保这不是某种内存管理问题。没提升。

对下一步有什么想法吗?

状态更新

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


问题答案:

更新: 潜在的核心数据问题似乎已在iOS 12.1(已在 beta 4中
验证)中得到解决。我们将在我们的应用程序中保留以下所述的解决方法,并且不建议您很快使用 外部存储 选项。

在与Apple工程师交谈并提交了上述Radar之后,我们迫不及待地想修复该问题,因此我们选择了解决方案,然后切换到将文件存储在文件系统上并直接对其进行自行管理。

我们考虑过的另一种选择是迁移模型,以不允许BLOB使用外部存储,但是我不知道这会对性能产生什么影响,并且我也担心在iOS的这一部分似乎无法迁移模型时不稳定,尤其是在阅读了过去这样的故事之后:核心数据:不要将大文件存储为二进制数据–
Alexander Edge –中

自己实施本地存储并没有太大的麻烦。您只需要为每个记录创建一个唯一标识符即可用于创建文件名,以便可以将文件映射到记录。我们向托管对象子类添加了扩展,其中包括用于读取,写入和删除文件的方法。现在,代替调用eg
article.photo =image.pngData(),我们现在需要调用类似的东西article.savePhoto(image.pngData()),然后在要检索图像时执行类似的操作。您还可以向这些方法添加一些代码,以支持与当前存储在Core
Data中的任何图像的向后兼容性。

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

最后,为防止当非可选二进制属性由于此错误而消失时,我们的应用崩溃,我awakeFromFetch在托管对象子类中进行了重写,以确保所有必需属性都不为零,如果是,则将其设置为占位符图像这样就可以保存它们而不会导致验证失败。



 类似资料:
  • 我有一个运行测试的Gradle文件。它不建造任何东西。它只有一个解压任务,将渐变配置中的所有JAR提取到特定目录中,然后运行类型测试任务。此测试任务将testClasses目录指向上一个复制任务将配置提取到的位置。 我的构建失败,并显示错误消息: 从二进制存储读取数据时出现问题 当我运行“gradle dependencies”时,它不会显示任何错误/警告。当我单独运行复制任务时,它运行得非常好。

  • 我们平时使用的数字都是由 0~9 共十个数字组成的,例如 1、9、10、297、952 等,一个数字最多能表示九,如果要表示十、十一、二十九、一百等,就需要多个数字组合起来。 例如表示 5+8 的结果,一个数字不够,只能”进位“,用 13 来表示;这时”进一位“相当于十,”进两位“相当于二十。 因为逢十进一,也因为只有 0~9 共十个数字,所以叫做十进制(Decimalism)。 进制也就是进位制

  • 问题内容: 我们正在捕获大小可变(从100k到800k)的原始二进制字符串,并且我们想存储这些单独的字符串。它们不需要索引(duh),并且不会对该字段的内容进行任何查询。 这些插件的数量将非常大(用于存档),例如每天10,000。像这样的大型二进制字符串的最佳字段类型是什么?应该是还是其他? 问题答案: 就 PostgreSQL 而言,类型是不可能的。与目标相比,它更慢,占用更多空间并且更容易出错

  • 我们可以编写存储库的自定义实现:

  • 本文向大家介绍C语言二进制思想以及数据的存储,包括了C语言二进制思想以及数据的存储的使用技巧和注意事项,需要的朋友参考一下 我们平时使用的数字都是由 0~9 共十个数字组成的,例如 1、9、10、297、952 等,一个数字最多能表示九,如果要表示十、 十一、二十九、一百等,就需要多个数字组合起来。 例如表示 5+8 的结果,一个数字不够,只能”进位“,用 13 来表示;这时”进一位“相当于十,”

  • 波姆。xml 这是一个java配置文件。 这是redis服务器的配置文件 存储库 > Rest 创建: 阅读: 数据保存和读取相当好。我假设它们被保存到一个具有内存实现的redis数据库中,尽管我没有专门对此进行配置。我推断是因为当我通过redis cli发送命令时,我不会通过查询的键获得答案。 但是,当应用程序运行时,数据会被保存并读取。 停止应用程序然后启动应用程序后,数据丢失。 此外,我使用