Core Data: Fundamentals

Jul 19 2022 · Swift 5.5, iOS 15.4, Xcode 13.3.1

Part 2: Saving Launches

11. Creating Managed Objects

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 10. Challenge: Customizing the RocketLaunch Entity Next episode: 12. Inserting Data Into the Context

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 11. Creating Managed Objects

NS Managed Object Class Reference

Transcript: 11. Creating Managed Objects

Defining a RocketLaunch entity in the editor isn’t enough because you need a way to reference it in code and create instances of it.

As mentioned earlier, Core Data models are structured differently from other data types you may have encountered. Core Data stores this data in generic containers using key value entries but to make life easier you can represent the entities in code as managed object subclasses.

There are 2 ways you can do this. The first is to have Core Data do it for you and the second is to write it out yourself. Obviously you’re here to learn so you’re going to do the latter.

When you auto generate files Core Data splits the definition and functionality up into two files, so you’ll do the same. Add a new Swift file to the project in the Model group and name it RocketLaunch+CoreDataClass.

Replace the Foundation import with an import of the Core Data framework instead

import CoreData

Next you’re going to define RocketLaunch as a subclass of the NSManagedObject class

public class RocketLaunch: NSManagedObject {}

Because you are inheriting from the subclass you get a lot of behavior for free. All the underlying logic of storing the data using the right keys and values, are all taken care of. There’s one small addition you need to make to the class definition here.

By default Swift code is only exposed to other Swift code. Makes sense right? Well Core Data is an Objective-C framework so you need to let the Objective-C runtime know about this class.

That is as simple as annotating the class with the @objc attribute.

@objc public class RocketLaunch: NSManagedObject {}

If you auto generate this code, and you will later on in this course, you will notice that the annotation is often followed by the name of the class like so

@objc(RocketLaunch)

When exposing this class to the Objective-C runtime you can rename the class to avoid namespace collisions. Essentially what this’s doing is saying that when this class is referenced by the Objective-C runtime we want the name used to be RocketLaunch. The Objective-C convention for naming your classes is to put your initials in front as a two or three letter prefix so you might see that on occasion.

Alright so that’s it for the class definition. Add another file to the same group and name it RocketLaunch+CoreDataProperties. This is not essential and you could do this in one file but it’s how the autogenerated code is added so you’ll do the same for consistency. In here you’re going to define the interface I mentioned earlier. Since Core Data is going to store the values in generic dictionary-like containers with keys and values you want something nicer to work with in code. This is important because it’s super easy to make mistakes when using strings to reference keys everywhere.

Start by importing Core Data again.

import CoreData

and then define an extension of the RocketLaunch class you just created.

extension RocketLaunch {}

In this extension you’re going to add properties to interact with the attributes you defined in the model editor. First up is the name property.

var name: String

Alright so what kind of property should you define? You can’t define a stored property because you can’t do that in extensions. You might be thinking well I just defined a class a minute ago. Let’s go back to that file.

You could add the attribute as a stored property in the class

var name: String

But now you need to initialize this property with a value. You can side step this issue by making the property optional, but according to the model you defined in the editor this needs to be required.

You can also define an initializer for the class that accepts an initial value for the property.

init(name: String) {
  self.name = name
}

But how can you guarantee that this initializer is called when Core Data fetches data from the persistent store and initializes an instance of this class? You can’t really, so a custom initializer is not an option.

Let’s get rid of this code. Back in the extension of RocketLaunch you could define name as a computed property.

var name: String {}

But this doesn’t work either. Should you write the logic yourself to fetch the value from the store? No, since that is what Core Data does for you.

To tell the compiler that the storage for this property is handled by Core Data you need to add the @NSManaged keyword.

@NSManaged var name: String

With this in place, Core Data dynamically generates efficient get and set attribute accessor methods for properties that are defined in the entity of a managed object’s corresponding managed object model.

This is how Core Data can use generic data containers under the hood but provide us with a proper class instance to interact with the rest of our app. Pretty neat huh?

Go ahead and add the rest of the attributes as managed properties.

@NSManaged public var name: String?
@NSManaged public var isViewed: Bool
@NSManaged public var launchDate: Date?
@NSManaged public var launchpad: String?
@NSManaged public var notes: String?

Now you have a class you can use. Before we wrap this up its worth mentioning, just like you couldn’t add stored properties to the class because it messed with how Core Data initialized the class, there are other aspects, certain methods in particular, that you shouldn’t override because Core Data expects managed object subclasses to behave a certain way. We also have one tiny thing left to do.

Navigate to the RocketLaunches.xcdatamodeld file, select the RocketLaunch entity and open up the data model inspector. Earlier when I walked you through this section we skipped this one right here that says Class. Remember how I said that Core Data can generate the managed object subclasses for us? If you go to the Editor menu, there’s a “Create NSManagedObject subclass” option at the bottom; don’t worry you will use it later.

In this section right here is where we map the Entity in the editor to the subclass in code. You should see the name RocketLaunch here and the codegen field set to Class Definition. Go ahead and change that to Manual/None to indicate that you wrote it out yourself. Hit Cmd+B to build the app and verify that everything compiles properly.

Alright, in the next video let’s talk about creating instances of this class and saving rocket launches!