Search code examples
swiftcore-datacompression

Compress CoreData data


I store data including a complex Dictionary in CoreData using the Transformable type.
I noticed over time that the CoreData sqlite database grew quite large.

I tested storing the data as a Binary Data type (NSData) and compressed the data using lz4 before saving. I could reach 30% reduce in size (and 45% using lzma).

As the Transformable type in general does the same (converting to a Data object) I'm wondering if it is possible to enable compression using this way.


Solution

  • Yes, if you implement your own value transformer. By default Core Data uses NSCoding to convert to and from binary data. You can replace that with whatever code you want, and Core Data will call that code at the appropriate times.

    First you implement the transformer, as a subclass of ValueTransformer. A minimal implementation would be something like

    @objc(MyDataTransformer)
    public final class MyDataTransformer: ValueTransformer {
        public override func transformedValue(_ value: Any?) -> Any? {
            // Your compression code here, returning Data
        }
        
        public override func reverseTransformedValue(_ value: Any?) -> Any? {
            // Your decompression code here, returning your custom data type
        }
    }
    

    Next you tell Core Data to use this for your transformable property by adding it in the model editor. Select the property and enter the value transformer class name in the "Transformer" field.

    Part of the "attribute" section of the Core Data model editor with the "Transformer" field highlighted and the class name "MyDataTransformer" entered in the field.

    Core Data will now use your code whenever it needs to read or save the property.

    There's an Xcode bug (which seems to have been around for a while...) where it complains that there's no NSValueTransformer with the class name you use, even though the app will work normally. Put a breakpoint in your class somewhere to verify that it's being used. Update: Someone just posted a good way to suppress the warning and make sure everything's working as expected.

    Finally, be sure to consider all the implications of this. You're performance for data store size when you do this. How much data are you saving, and how does that compare to the performance hit from your compression and decompression? Make sure it's worth the price.