允许外部存储崩溃的核心数据二进制数据

Posted

技术标签:

【中文标题】允许外部存储崩溃的核心数据二进制数据【英文标题】:Core data binary data with allows external storage crashes 【发布时间】:2018-11-14 13:03:32 【问题描述】:

我在 ios 12.0.1 上出现以下日志崩溃:

ImageIO: CFDataGetBytes: data: 0x28539b2f0 size: 154262 offset: 8 count: 8 dst: 0x16dbf86f0
    External data reference cant find underlying file.
    Fatal Exception: NSInternalInconsistencyException
        0  CoreFoundation                 0x23c2d7ef8 __exceptionPreprocess
        1  libobjc.A.dylib                0x23b4a5a40 objc_exception_throw
        2  CoreData                       0x23efd5fc8 -[_PFExternalReferenceData getBytes:range:]
        3  ImageIO                        0x23e6c7178 IIOImageRead::getCFDataBytesAtOffset(void*, unsigned long, unsigned long)
        4  ImageIO                        0x23e6c6c38 IIOImageRead::getBytesAtOffset(void*, unsigned long, unsigned long)
        5  ImageIO                        0x23e711aa4 IIO_Reader_PNG::getImageCount(IIOImageReadSession*, IIODictionary*, int*, unsigned int*)
        6  ImageIO                        0x23e54c5d8 IIO_Reader::callGetImageCount(CGImageReadSession*, IIODictionary*, int*)
        7  ImageIO                        0x23e532194 IIOImageSource::updatedCount()
        8  ImageIO                        0x23e5367b4 CGImageSourceGetCount
        9  UIKitCore                      0x26960c1a4 _UIImageRefFromData
        10 UIKitCore                      0x268d4e15c -[UIImage(UIImagePrivate) _initWithData:preserveScale:cache:]
        11 UIKitCore                      0x268d48b7c +[UIImage imageWithData:]
        12 MyApp                          0x102239570 __48-[InfoPreviewController bindToPatient:]_block_invoke_2 (InfoPreviewController.m:83)
        13 ReactiveObjC                   0x1031f8004 -[RACSubscriber sendNext:] (RACSubscriber.m:72)

似乎核心数据有图像,但是当它试图检索它时,它失败了。

在这种情况下如何验证数据完整性? 我想以用户友好的方式处理此故障,而不是让应用程序崩溃。

【问题讨论】:

【参考方案1】:

这是由 iOS 12.0.x 中 Core Data 外部存储中的一个已知错误引起的,如下所述:https://***.com/a/52628198/2347353。没有解决方法,但该错误似乎已在 iOS 12.1 中修复。

不过,为了回答您的问题,您可以通过一些hackery-pokery 获取假定要存储数据的文件名,并检查它是否存在。如果文件丢失,那么您就知道发生了损坏,因此您可以避免读取该属性,从而防止应用程序崩溃。

这些都没有记录,但文件似乎存储在应用程序 Documents 文件夹中的 _EXTERNAL_DATA 隐藏目录中,文件名可以从保存到数据存储的值中计算出来。

这个答案显示了如何在 Objective-C 中执行此操作,并且我从以下位置获得了很多详细信息:https://***.com/a/13497992/2347353。但对于在家尝试此功能的任何人,请注意警告,这一切都基于 Apple 的 Core Data 内部实现细节,并且可能在未来的任何时候停止工作。

【讨论】:

感谢@rodhan。我想指出,路径已从Documents 更改为Library/projectname (iOS12)。确实非常hacky。 您知道如何强制核心数据使用Allow External Storage 进行测试吗?我尝试添加一个大图像,希望核心数据逻辑能够启动并将文件移动到外部存储,但似乎并非如此。【参考方案2】:

崩溃可能是由于没有对外部存储文件夹的文件访问权限。

因此,在使用 attribute.description?.allowsExternalBinaryDataStorage == true 访问对象值之前,请确保您有权访问或有权访问存储 Core Data SQLite 数据库文件的文件夹。

【讨论】:

以上是关于允许外部存储崩溃的核心数据二进制数据的主要内容,如果未能解决你的问题,请参考以下文章

如何防止备份带有外部文件的 Core Data 数据库?

在 iPhone 上的核心数据中存储二进制数据

SharePoint 2013 使用 RBS 功能将二进制大型对象 BLOB 存储在内容数据库外部。

在核心数据中存储 UUID

Core Data 删除外部存储实体不会释放 iCloud 中的空间

可转换数据和二进制数据有啥区别