Recently, I saw a post from Dave DeLong and knowing his history with the framework I read it with extreme curiosity.
Unfortunately, that read led to this post as I disagree strongly with a number of the laws he has laid down.
Since I know people are going to be asking me about this post (I am still getting asked about Simmons’ post from a VERY long time ago), better to get my thoughts out now.
1. Do not use Core Data as if it were a database
No disagreement; Core Data is your object model and it can persist to a database but that is not its biggest strength.
2. Do not use Core Data as if it were a SQLite wrapper
This is re-iterating #1. Core Data is your object model, not a thin wrapper around a database.
NSManagedObjectContext is your “stack”
Here is where we start to disagree. The
NSManagedObjectContext is not your stack. It is a scratchpad. It is where you stage changes to the data objects and decide to persist them or not.
I have advocated putting an object around it for convenience and Apple added the
NSPersistentContainer which is designed to be subclassed. That wrapper is a great place to handle migrations, importing, exporting, convenience methods for accessing data; the list goes on.
All of the internal workings of your Core Data stack, your persistence and data model absolutely should be stored in the persistent container and that container should be injected through your controllers in your application.
4. Never ever ever ever ever use an
NSManagedObject outside its context’s queue
No disagreement. Core Data is designed to work in a threaded environment but most of the objects are NOT designed to work on multiple threads/queues. As with ANY object, assume it is thread locked unless you can demonstrably confirm that it is safe to use across threads.
5. Do not use
NSManagedObject as if it were an
NSManagedObject is an
NSObject that has additional functionality added. It should absolutely be treated as if it is an
NSObject because it is an
NSManagedObject instances are your data objects and should be treated as such. Creating Plain Old Objects on top of
NSManagedObject instances is asking for pain and data corruption.
6. You usually don’t need parent-child contexts
If you are not accessing the network, exporting data, importing data or interacting with the outside world in any way, shape or form then this is correct.
If your app talks to anything else then you will want to use parent-child contexts.
The parent context should be on the user interface thread (the main thread) and when you need to do asynchronous work with your data objects (importing or exporting) then you want to do that on another thread and that work should be done in a child context.
A child context simplifies the transfer of notifications of data changes and greatly simplifies using Core Data in a multi-threaded environment.
7. Keep your main queue context read-only
The main queue is also known as the user interface queue. The context that is associated with that queue should be for the user. That context reads and writes data when the user is interacting with the application.
Should it be read-only? Absolutely not.
Should it be user-only? Absolutely.
Any non-user work (importing and exporting) should be done on a child context on a background thread (see response to #6 above).
8. Use an abstraction layer
Please do not do this. You are going to make the next developer curse your name in a very unpleasant manner.
Use Core Data in your user interface. Do not create dummy data objects on top of Core Data. That leads to a maintenance nightmare.
Your user interface can use Core Data without really knowing that it is using Core Data. Your user interface treats the
NSManagedObject instances as if they were data objects because they are data objects.
Your user interface does not need to know any more about Core Data than it does for any other model structure. Your user interface should talk to your persistent container subclass and ask for the data it needs. The response to that request might be instances of
NSManagedObject or might be an
NSFetchedResultsController which then serves up the data objects in a consistent and reliable way.
9. Use Core Data as a local cache
I agree with the wording of this rule but I suspect the meaning is different. Core Data, like any local persistence, is a local cache of what is on the server. This is not specific to Core Data because that is what any local persistence does when you have data on a server.
Core Data is more than just a local cache.
Core Data is not complicated
Core Data is as complicated as you make it. Most of the time you do not need or want the advanced features of Core Data and can just grab an instance of
NSPersistentContainer and be happy.
When you need to deal with more complicated or interesting situations there is a fair chance that Core Data has an advanced feature to handle that situation. For the 80%, you can ignore those advanced features and relax in the comfort knowing they are there for if/when you need them.
The harder your code is to write the harder it is going to be to maintain and debug.
Don’t make it harder on yourself. Keep it simple.
It is time to move on to the next chapter.
What is Next?
Long term I have some ideas that will take a bit of time to put into place. In the short time I am eager to help as many teams as possible through short term contracting, consulting and workshops. I really do enjoy helping teams get the most out of their persistence and networking layers.
Effective immediately, I am available for short term and possibly long term contract work.
While I can assist with any form of iOS or OS X development, my area of expertise is in networking and persistence; specifically Core Data.
If you are not familiar with my experience, here are a few highlights:
- Wrote “The Book” on Core Data.
- Taught at universities around the United States
- Spoken at nearly every Apple related tech conference around the world
- Provided workshops on persistence, Core Data and Networking at many conferences and large corporations in and around the United States.
- Developed some of the most complex applications ever conceived for the iOS platform
What are the options?
I am looking for short term projects unless it is truly amazing, cutting edge, and never done before. I am looking to help your team provide a better experience for your users.
We can accomplish this either through a monthly, weekly, daily contract or through a workshop. The details of which we can discuss in detail. I am available to travel and can work on site for short periods of time.
Are you struggling with your persistence or networking layer?
Are you having performance issues that you are unable to isolate?
Would you like a fresh set of eyes on your project to get an idea of where things are?
Contact me; we can discuss the options.
You can find other articles on the interwebs about
NSExpressionDescription, however, I wasn’t really satisfied with the explanations I’ve seen. I decided to write a post myself after I recently had to become much more intimate with the way Core Data aggregate fetches work. I hope this will make clear what has to be done in order to harness this powerful feature of Core Data.
You’ve heard it said before and sometimes in a scolding tone, “CORE DATA IS NOT A DATABASE. IT’S AN OBJECT GRAPH!”. What normally follows is a discussion about what that means, if you’re lucky. Otherwise, you’re just on your own to go figure it out. In my mind, though, it’s not necessarily wrong to think of it as a database as they have enough things in common to make it a reasonable thing to do and at the end of the day Core Data is backed by a SQLite database. I think that if it helps you understand what is going on behind the scenes better, then go for it. You do have to remember some key differences that can bite you like the need to fetch before updating or deleting, for example. Though with recent additions–last year with iOS 8’s NSBatchUpdateRequest (link to iOS 8 API diff since it’s not currently documented) which allows you to perform a batch update similar to a SQL update query or this year with iOS 9’s
NSBatchDeleteRequest (See WWDC 2015 session 220 for more info) which allows for batch deletes based on whatever predicate you give it, the lines seem to be blurring more and more. (more…)
Sometimes you have a set of objects you want to display in the same form–say, for example, in a table view controller. What if those objects have, by design, nothing in common and nothing to do with each other? This is a case where you can create and conform to a protocol–known in some languages as an interface–to provide a simple way to have each class type provide a display name that can be displayed in your table view controller.
Recently while using this language feature writing Swift code, I ran into a few snags and learned from the process. I figured I would document it in this screencast. It walks you all the way through from project creation, so it’s about 35 minutes.
Here’s what you will learn:
- How to setup CoreData entities in the data model
- How to add a run script action to build your managed object classes using mogenerator
- How to create a protocol in Xcode 6
- How to implement a protocol in the various managed object classes
- How to preload your CoreData store with test objects in code
- How to load each object type generically into a table view controller
And if you want to just cut to the chase, grab the code from github.
Whenever Apple releases a new version of Xcode one of the first things that I do is look at the default templates and see if there are any new or interesting things.
This year, with the release of Swift, there are some pretty radical changes. Yet the Core Data stack initialization code is still the same.
There is nothing wrong with the default template code but there isn’t really anything right about it either. It is far better than it once was but it is still overly verbose and hard to follow.
Therefore, I present my Swift Core Data stack code that I will be using as I grok this language.
I very rarely speak out against another blog post. I find the resulting argument back and forth draining. However, there are exceptions and one occurred over the weekend.
Brent Simmons has been blogging about his conversion of Vesper to a Core Data application. A recent post of his titled Core Data and Deleting Objects set my teeth on edge. Brent says:
“The best advice I’ve heard about deleting managed objects is to 1) not do it, or 2) do it only at startup, before any references to those to-be-deleted objects can be made.”
I do not know who is giving Brent advice but he must be playing tricks with him or just trying to wind him up. The advice was simple; don’t delete Core Data objects or if you are going to delete them, delete them at launch.
Will that work? Sure. Is it the right answer? Not even close.
Core Data and NSFetchedResultsController do clever things under-the-hood to improve performance, such as loading data in batches as it’s needed. But there’s a gotcha with grouping data with sectionNameKeyPath than can cause a big hit in performance. Check this out.
Importing data is a problem that feels like it should have a library of work ready for you to use. Especially when it comes to importing data into Core Data where you have a description of your data to work with. What if there was such a library, or reusable framework, of importing code that basically converts raw data to Core Data entities? Well, wonder no further because in this post, I’ll be discussing a new addition to the MagicalRecord toolset, MagicalImport available now on Github!
Whether you subscribe to Test Driven Development (TDD) or another testing practice, when it comes automated unit testing with Core Data, things can be a little tricky. But if you keep it simple, and take things step by step, you can get up and running with unit testing using Core Data fairly quickly. We’ll explore the what, how and why of unit testing with Core Data. We’ll also be using the helper library MagicalRecord. MagicalRecord not only lets us get up and running faster, but helps to cut down on the noise in our tests.
A few months ago I wrote here about a generic approach to safely take incoming JSON and save values to Core Data object. The goals of that code were twofold:
- Provide a safe, generic alternative to Cocoa’s
-setValuesForKeysWithDictionary:for use with NSManagedObject and its subclasses
- Handle cases where JSON data didn’t match up with what the managed objects expected. Getting a string where you expect a numeric value, or vice versa, for example, or getting a string representation of a date when you want a real NSDate object.
The first item was the most important. It’s tempting to use
-setValuesForKeysWithDictionary: to transfer JSON to a model object in one step. The method runs through the dictionary and calls
-setValue:forKey: on the target object for every entry. It has a fatal flaw though, in that it doesn’t check to see if the target object actually has a key before trying to set it. Using this method when you don’t have absolute control over the dictionary contents is an invitation to unknown key exceptions and nasty app crashes.
Fixing this for managed objects was relatively easy because Core Data provides convenient Objective-C introspection methods. The general approach was:
- Get a list of the target object’s attributes
- For each attribute, see if the incoming dictionary has an entry. If so,
- Compare the incoming type to the expected type, and convert if necessary.
-setValue:forKey:with that key and its value.
And then just last week I had the thought, wouldn’t it be nice if this worked for any object, not just for managed objects?
Recently on [StackOverflow](http://stackoverflow.com) I have seen several questions regarding the desire for a parent Entity to be updated whenever an attribute within the child has changed.
There are several different ways to solve this problem. The easiest is to have the child ping the parent whenever it changes and then the parent can update any values it needs to as a result of that ping.
*Note: This is a re-print from the Mac Developer Network.*
One of the nice things about developing software for OS X is all the “freebies” we get out of Cocoa. For example, when we are building a UI with text input we get undo support for free! How cool is that?
Likewise, when we are working with Core Data, it also has undo support built right in. Every
NSManagedObjectContext has a NSUndoManager that we can use. However there are some situations where the default undo support is insufficient.
In this article we are going to walk through one such situation.
*Note: This is a re-print from the Mac Developer Network.*
I tend to frequent the StackOverflow website and watch for questions about Core Data. Generally if it is a question I can answer I will and if it is a question I can’t answer then I really dig in for a fun session of exploration and attempt to find the answer.
Core Data has many features, one of which is the Transient attribute. This type of attribute on a Core Data entity is part of a data model, but is not persisted in your Core Data persistent store. If you open up the raw SQLite store file and peek at the schema, you will not find any transient attributes. These transient attributes are still handy despite no data being persisted to the data store. One useful scenario is when a value is calculated based on other attributes. This calculation can be performed in an entity’s awakeFromFetch method, and stored at run time in this transient attribute.
One scenario I’ve been asked about on more than one occasion recently is that of temporary, or transient entities. It seems that more and more developers have a need for temporary, or transient instances of entities in your Mac or iOS apps. Having temporary object instances can be useful and necessary in certain situations. Unfortunately, Transient Entities do not technically exist within the Core Data framework, however there are simple solutions to add temporary, un-persisted, data within the context of Core Data. Let’s go over some methods to effectively use the concept of Transient, or more appropriately Temporary Entities in Core Data without direct built-in support.
Hi, I’m new here. You may know me as @atomicbird on Twitter. Just a few days ago my book Core Data for iOS: Developing Data-Driven Applications for the iPad, iPhone, and iPod touch (co-written with the excellent Tim Isted) was published, and Matt invited me to contribute some Core Data tips to CIMGF. I’m going to start off discussing taking JSON data from a web service and converting it to Core Data storage. Along the way I’ll cover how to inspect managed objects to find out what attributes they have and what the attribute types are.
Publishing lead times being what they are, this post covers information not included in the book.