Using Core Data with Swift

Published on February 20, 2015

knowledge-base-white-paper

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

This is a second article in our development-focused series in which we talk about the development challenges we face, sharing our learnings and findings with the community. In this post our iOS developer Boris introduces workarounds for some common issues when using Core Data with Swift and shows how Swift is different from Objective-C in this particular aspect. As an interested mobile developer, you might also want to take a look at the first article in this series, Android and the DEX 64K Methods Limit.

While implementing the example iOS apps for our blog space template, we were using Core Data with Swift for the first time seriously. In this post you will learn about some caveats and changes from using Objective-C.

Documented changes

The most interesting part of using Core Data with Swift is that it requires the use of the dedicated @NSManaged attribute, which is a special flavour of dynamic. What this means is that it tells the compiler that the storage and implementation of the property will be provided at runtime, similarly to the @dynamic attribute in Objective-C. As we will learn in the rest of this post, it seems as if this is providing a fairly specific behavior which currently breaks a number of Swift features. Apple's documentation doesn't talk much about this fact and only mentions that one has to include the module name when defining class names for an entity in the Core Data editor. Currently, it’s also necessary to perform this step manually when using our Xcode plugin to generate a data model, but we are working on it.

coredatanamespace 2x

ContentfulPersistence was using NSStringFromClass() to determine the entity name from the class name when creating new objects during synchronization. Unfortunately, the string representation of a Swift class will also include the module name, but the entity name will not. For that reason, our CoreDataManager now removes the module name prefix before creating new entities. This is just something to keep in mind if you dynamically create NSManagedObject instances from class names.

Optional attributes

Long before Swift gave us optionals, we could define optional properties in Core Data models. Their semantics were a bit different, namely saving a managed object with a non-optional property fails if it has never been given a value. Still, it seems like a reasonable expectation that since an optional property can be nil at any point in time, it should be a Swift optional in the generated NSManagedObject subclasses. However, this is not the case, and unless you manually change that, you will not be able to check if a property is nil, because the Swift compiler does not know that it can have no value. So you should make sure to correctly mark all optional model attributes as Swift optional properties in your model code and also reasonably ensure that all the other properties are never nil to begin with – for example, by adding default values to your model. This was reported as a radar, feel free to duplicate.

Implementing protocols

Now it is getting more messy. The way ContentfulPersistence works is that you are expected to implement certain protocols provided by the Contentful SDK in your NSManagedObject subclasses, so that we can ensure that all required properties exist, but if one does that with a class written in Swift:

So what is even going on here? Swift uses symbol mangling in its code generation process, and the swift-demangle tool that comes with Xcode allows us to demangle them:

A materializeForSet function is usually used to set an initial value for a property. Because @NSManaged properties are entirely dynamic, this function does not exist for managed properties at all. However, some part of the Swift compiler still generates code which uses it, apparently. I have yet to look more deeply into that part, as I was more interested in fixing it. By using subclassing or Swift property observing we can fool the compiler in generating all the required code, but that will break @NSManaged entirely – more on that in the next section. Since we know that the missing function is not really needed anyway, how about fooling the compiler about its presence?

Let's add a simple C file to our project:

and voilà , the project builds and runs just fine. We have fooled the compiler to believe that the missing function is actually present and nobody ever calls it at runtime anyway. It is quite a hack, but for now, we have to live with it, meanwhile reporting it as another radar, which also contains some minimal example code for reproducing this.

Using property observers

I mentioned earlier that using property observers will cause the compiler to generate slightly different code, so as a final exercise, let us look at that. Consider this code:

It compiles just fine, but will actually cause the dynamic nature of @NSManaged to fail at runtime with a crash if one tries to work with such a property. I have also reported this as a radar and you should generally avoid any kind of override of managed variables, as this compiles just fine, but will break at runtime.

Conclusion

Using Core Data with Swift has some rough edges, but it is possible to avoid them all once you know them. Take a look at our example iOS apps as an example.

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

Related articles

This guide will show you how to create a Next.js application using App Router to fetch knowledge base articles from Contentful via React Server Components.
Guides

How to Integrate Contentful and Next.js App Router

December 13, 2023

In this tutorial, we'll build a basic Svelte app that will give you a good understanding of the core concepts in Svelte-like components, props, and more.
Guides

Svelte tutorial: An elegant framework for learning new things

September 6, 2023

Illustrated image showing how rich text is rendered with JS
Guides

How to build a CMS using JavaScript with Contentful

November 29, 2022

Contentful Logo 2.5 Dark

Ready to start building?

Put everything you learned into action. Create and publish your content with Contentful — no credit card required.

Get started