Why I abandoned Core Data

Arik Sosman
3 min readMar 28, 2014

--

When I set out to develop my first big iOS app, I had only had about two months of prior experience with Objective-C. In addition to that, I had not previously spent a lot of time writing big client-side applications. Pretty much all the work I had done before was developed in PHP, and I seldom gave much thought about how to store data — MySQL had always been the obvious choice.

Until that app. My first ideas were rather primitive, vacillating somewhere between saving a huge file containing some JSON, or another huge file which would contain the output of an NSKeyedArchiver, whose input would be a gigantic NSDictionary. An even more stupid idea had been not to store any local data, and always reload it whenever starting the app, downloading all the relevant server content anew. My experience with web projects was showing, but it was not applicable. Within a few hours, the realization hit me that a local database was necessary.

A quick Google search yielded immense praise for Core Data. It looked highly promising: automatically managed objects, convenient relationship management, easily modifiable columns, integration with iCloud — who in their right mind would refuse such a convenient framework?

The alleged convenience came with a price, though. The app I was building relied (and still does) rather heavily on encryption and decryption. There is a lot of data, and it is all encrypted separately — that is, there is not one huge chunk that only has to be processed once, but a lot of very tiny fragments. While AES encryption is fast, it is not the size of the file that has the biggest impact on the duration, but the amount of distinct decryptions. (That can be easily seen when looking at AES decryption time in relation to the size of the data.) In order to not block the UI thread, I moved the encryption parts to background threads. That way, data would be received from the server, then sent to a background thread, decrypted, sent back to the main thread and saved using Core Data.

Core Data does not like being called from a background thread, however. Doing that would lead to occasional freezes. There were no errors per se, and a breakpoint set to all exceptions did not yield any results. The app would simply freeze, even in debugging.

So I created a multitude of NSManagedObjectContexts, each in its own thread, and then merge them. The app stopped crashing, but the saving process also stopped being deterministic. If data was sent from the server modifying one attribute of an object, while the user modified another, only one of the two values would be saved. That error arose when an object was fetched in both threads before changes were done in either.

It was even worse when several background threads changed different properties. When the program, rather than the user, had to process several changes, it did not even help to fetch the respective object immediately before changing the attribute and saving it, due to a time difference of some 70ms when merging changes from different threads.

So I moved to FMDB. Suddenly, multiple threads just worked. They worked pretty much the same way Core Data never had, but should have. All database operations were added to a thread-safe queue, and were processed in order. Additionally, complex queries could be saved in SQLite views and easily accessed where previously rudimentary queries had to be built with Core Data’s own, weird, query syntax, to be post-processed with numerous lines of code.

The app has neither been freezing, nor neglecting to properly save data ever since. That I know of.

--

--