Creating Data Models in Swift With Core Data

Because of the lack of a built-in utility for creating data models for Core Data entities, a lot of tools have popped up to make developers' lives easier. Most notably among them, mogenerator. Mogenerator accomplishes a number of things. For sake of later comparison, I'll list a few of the most useful mogen features:

  1. Simple, easy creation of classes for your data model.
  2. Pattern of two-class creation -- allows you to have and keep custom code without risk of overwriting it, while still maintaining flexibility to update your entity's attributes in .xcdatamodel. Updates regenerate the second file, leaving the entity class file and added custom code in tact.
  3. Convenience methods to access the attributes of your entities.
  4. Scalar accessors that let you access BOOLs, integers, floats, instead of just NSNumbers.

I'm currently working on a project in Swift, which means another chance to reevaluate existing patterns and old habits that may or may not fit into the Swift paradigm. On a side note, hasn't the release of Swift been great on a meta level? I know of so many people and companies that have been able to use Apple's release of a new and powerful programming language as an opportune moment to fix or completely redo areas of their codebase that were dragging on the entire app (or company). Once you're caught in the technical debt trap, it's almost impossible to get out. But it is possible. And fortunately for us, Swift makes it easier and faster than ever before to write clean, maintainable, beautiful Cocoa apps.

I was recently at a SLC CocoaHeads meetup and asked the group if many people still use mogenerator in predominantly Swift projects. I was immediately directed to an Xcode feature that I've missed amongst all the other Apple news, a job change, and a relocation from SF to SLC over the past few months. Or maybe this came out with Swift 1.0? I'm not entirely sure. Either way, they told me Xcode can now generate classes for your models in a two-class pattern similar to mogen. Of the four mogen features mentioned above, the first two are now seamlessly integrated into Xcode + Swift.

To be fair, creation of NSManagedObject subclasses was always possible... and from Xcode 4.3 you've been able to do it from the Editor Menu too (pictured below). I actually wasn't aware of the Editor Menu trick... my experience with Core Data comes from working with it on two previous occasions. On one I was contracting with the team for six weeks. It used mogenerator and was my first exposure. My involvement with Core Data there was limited to referencing the data model and minor tweaks. The second project's Core Data implementation was completely manual. I took over the project and worked on it as the sole developer. Two very contrasting approaches, both suiting their needs just fine.

Back to the Swift + Core Data goodness, by selecting your .xcdatamodel file and opening the Editor Menu from the Menu Bar, you'll be given a contextual set of options relating to Core Data. Select Create NSManagedObject Subclass, select the data models and entities you'd like to manage (select all for the first time, select one or a few for an update), select the destination directory and create. This will create two files for you. The first is a subclass of NSManagedObject and represents your entity. The second creates an extension (similar to the Objective-C categories approach) called EntityName+CoreDataProperties.

//
//  User.swift
//  Perspectives
//
//  Created by Kyle Clegg on 11/19/15.
//  Copyright © 2015 Kyle Clegg. All rights reserved.
//

import Foundation
import CoreData


class User: NSManagedObject {

// Insert code here to add functionality to your managed object subclass

}
//
//  User+CoreDataProperties.swift
//  Perspectives
//
//  Created by Kyle Clegg on 11/19/15.
//  Copyright © 2015 Kyle Clegg. All rights reserved.
//
//  Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
//  to delete and recreate this implementation file for your updated model.
//

import Foundation
import CoreData

extension User {

    @NSManaged var email: String?
    @NSManaged var password: String?
    @NSManaged var name: String?
    @NSManaged var userId: NSNumber?
    @NSManaged var collections: NSSet?

}

As the comments auto-generated by Apple note, EntityName+CoreDataProperties.swift will be scratched and regenerated when you run through the process again after you update your model in the future. That's the beauty of it. Any convenience methods, helpers, accessors, etc. that you may want to include should be added to the entity's class, and updates are handled by Xcode without destroying your code in the entity's class.

Gotchas? Nothing major really. I suppose two minor things are that CMD-clicking the entity when it appears in code in other places can bring you to an empty User.swift file when what you really wanted to see were the properties. A little annoying, but understandable. A second one is that when you regenerate models after a property update or addition Xcode doesn't overwrite the EntityName+CoreDataProperties.swift file. It creates a second one. Just select one of the two (either one), hit delete and select Remove Reference. ¯\_(ツ)_/¯

So there it is. Simple data model creation and updates using Swift extensions and native Xcode integrations. I should note that we are losing some functionality provided by mogenerator, but I'm okay with that for now. Mogenerator gave me way more functionality than I asked for, and I'll bring it back in the future if I feel like I need it. For now, I rest easy knowing that there's no magic going on, just simple, clean Swift Core Data code.