Entities

A relational database has something called a table. A table represents a type: You can have a table of people, a table of a credit card purchases, or a table of real estate listings. Each table has a number of columns to hold pieces of information about the type. A table that represents people might have columns for last name, date of birth, and height. Every row in the table represents an example of the type – e.g., a single person.

This organization translates well to Swift. Every table is like a Swift type. Every column is one of the type’s properties. Every row is an instance of that type. Thus, Core Data’s job is to move data to and from these two representations (Figure 22.1).

Figure 22.1  Role of Core Data

Illustration shows the role of core data.

Core Data uses different terminology to describe these ideas: A table/type is called an entity, and the columns/properties are called attributes. A Core Data model file is the description of every entity along with its attributes in your application. In Photorama, you are going to describe a Photo entity in a model file and give it attributes like title, remoteURL, and dateTaken.

Modeling entities

Open Photorama.xcodeproj. Create a new file, but do not make it a Swift file like the ones you have created before. Instead, select iOS at the top and scroll down to the Core Data section. Create a new Data Model (Figure 22.2). Name it Photorama.

Figure 22.2  Creating the model file

Screenshot shows the creation of a model file.

This will create the Photorama.xcdatamodeld file and add it to your project. Select this file from the project navigator and the editor area will reveal the UI for manipulating a Core Data model file.

Find the Add Entity button at the bottom left of the window and click it. A new entity will appear in the list of entities in the lefthand table. Double-click this entity and change its name to Photo (Figure 22.3).

Figure 22.3  Creating the Photo entity

Screenshot shows the creation of a photo entity.

Now your Photo entity needs attributes. Remember that these will be the properties of the Photo class. The necessary attributes are listed below. For each attribute, click the + button in the Attributes section and edit the Attribute and Type values.

  • photoID is a String.

  • title is a String.

  • dateTaken is a Date.

  • remoteURL is a Transformable. (It is a URL, but that is not one of the possibilities. We will discuss transformable next.)

Transformable attributes

Core Data is only able to store certain data types in its store. URL is not one of these types, so you declared the remoteURL attribute as transformable. With a transformable attribute, Core Data will convert the object into a type that it can store when saving and then convert it back to the original object when loading from the filesystem.

Core Data works with classes under the hood because it is an Objective-C framework. So instead of working with an instance of URL (which is a struct), you will work with an instance of NSURL (which is a class) when dealing with Core Data. Swift provides a mechanism for converting a URL to an NSURL and vice versa, which you will see later on in this chapter.

A transformable attribute requires a ValueTransformer subclass to handle the conversions between types. If you do not specify a custom subclass, the system will use the transformer named NSKeyedUnarchiveFromDataTransformer. This transformer uses archiving to convert the object to and from Data. Because NSURL conforms to NSCoding, the default NSKeyedUnarchiveFromDataTransformer will be sufficient. If the type you wanted to transform did not conform to NSCoding, you would need to write your own custom ValueTransformer subclass.

With Photorama.xcdatamodeld still open, select the remoteURL attribute and open its Data Model inspector on the righthand side. Under the Attribute section, enter NSURL as the Custom Class. This will allow Core Data to do the transformation for you.

At this point, your model file is sufficient to save and load photos. In the next section, you will create a custom subclass for the Photo entity.

NSManagedObject and subclasses

When an object is fetched with Core Data, its class, by default, is NSManagedObject. NSManagedObject is a subclass of NSObject that knows how to cooperate with the rest of Core Data. An NSManagedObject works a bit like a dictionary: It holds a key-value pair for every property (attribute or relationship) in the entity.

An NSManagedObject is little more than a data container. If you need your model objects to do something in addition to holding data, you must subclass NSManagedObject. Then, in your model file, you specify that this entity is represented by instances of your subclass, not the standard NSManagedObject.

Xcode can generate NSManagedObject subclasses for you based on what you have defined in your Core Data model file.

In the project navigator, select the Photo.swift file and delete it. When prompted, move it to the trash to make sure it does not still exist in the project directory.

Open Photorama.xcdatamodeld. Select the Photo entity and open the Data Model inspector. Locate the Codegen option and select Manual/None.

With the Photo entity still selected, open the Editor menu and select Create NSManagedObject Subclass…. On the next screen, check the box for Photorama and click Next. Check the box for the Photo entity and click Next again. Finally, click Create. There will be a few errors in the project. You will fix those shortly.

The template will create two files for you: Photo+CoreDataClass.swift and Photo+CoreDataProperties.swift. The template places all of the attributes that you defined in the model file into Photo+CoreDataProperties.swift. If you ever change your entity in the model file, you can simply delete Photo+CoreDataProperties.swift and regenerate the NSManagedObject subclass. Xcode will recognize that you already have Photo+CoreDataClass.swift and will only re-create Photo+CoreDataProperties.swift.

Open Photo+CoreDataProperties.swift and take a look at what the template created for you.

All of the properties are marked with the @NSManaged keyword. This keyword, which is specific to Core Data, lets the compiler know that the storage and implementation of these properties will be provided at runtime. Because Core Data will create the NSManagedObject instances, you can no longer use a custom initializer, so the properties are declared as variables instead of constants. Any custom properties or code that you want to add should be added to Photo+CoreDataClass.swift.

Let’s fix some of the errors that are in the project.

Open PhotoStore.swift and find fetchImage(for:completion:). This method expects the photoID and the remoteURL to be non-optional; however, Core Data models its attributes as optionals. Additionally, the URLRequest initializer expects a URL instance as its argument instead of an NSURL instance. Update the method to address these issues.

func fetchImage(for photo: Photo, completion: @escaping (ImageResult) -> Void) {

        guard let photoKey = photo.photoID else {
            preconditionFailure("Photo expected to have a photoID.")
        }
        if let image = imageStore.image(forKey: photoKey) {
            OperationQueue.main.addOperation {
                completion(.success(image))
            }
            return
        }

        guard let photoURL = photo.remoteURL else {
            preconditionFailure("Photo expected to have a remote URL.")
        }
        let request = URLRequest(url: photoURL as URL)

To address the first issue, you are using a guard statement to unwrap the optional NSURL. To address the second issue, you bridge the NSURL instance to a URL instance using an as cast. The compiler knows that NSURL and URL are related, so it handles the bridging conversion.

You have created your model graph and defined your Photo entity. The next step is to set up the persistent container, which will manage the interactions between the application and Core Data. There are still some errors in the project; you will fix them after you have added a Core Data persistent container instance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset