Zsolt
Zsolt

Reputation: 3760

Core data binary data with allows external storage crashes

I have a crash with the following log on 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)

enter image description here

It seems that core data has the image, but when it tries to retrieve it, it fails.

How can I verify the data integrity in this case? I would like to handle this failure in a user friendly way instead of crashing the app.

Upvotes: 3

Views: 1090

Answers (2)

Ely
Ely

Reputation: 9141

The crash can be caused by not having file access to the external storage folder.

So before accessing an object value with attribute.description?.allowsExternalBinaryDataStorage == true, make sure you have access or get access to the folder where the Core Data SQLite database files are stored.

Upvotes: 0

rodhan
rodhan

Reputation: 643

This is caused by a known bug in Core Data external storage in iOS 12.0.x as discussed here: https://stackoverflow.com/a/52628198/2347353. There is no workaround, but the bug appears to be fixed in iOS 12.1.

To answer your question though, with a bit of hackery-pokery, you can get the filename where the data is supposed to be stored and check to see if it exists or not. If the file is missing, then you know that the corruption has happened so you can avoid reading the attribute, and therefore prevent the app from crashing.

None of this is documented, but the files seem to be stored in the _EXTERNAL_DATA hidden directory in your app’s Documents folder with a filename that you can work out from a value that is saved to the data store.

This answer shows how to do this in Objective-C and is where I got a lot of the details from: https://stackoverflow.com/a/13497992/2347353. But for anyone trying this at home, please do heed the warnings that this is all based on Apple’s internal implementation details of Core Data and could stop working at any point in the future.

Upvotes: 2

Related Questions