CHAPTER 9

image

Using SQLite/Core Data with Swift (iOS and OS X)

After looking at the Xcode Core Data model editor which lets you build your Core Data environment graphically, it’s time to move to the code that implements it. Core Data wraps the persistent store, which in many cases is the built-in SQLite library for OS X, iOS, watchOS, and tvOS.

This chapter looks at the Core Data stack—the objects that do the work in all cases. It also looks at the specific objects that you may use in implementing your own app.

The SQLite syntax that is exposed in other environments is still working here, and, as you saw in Chapter 8, in the discussion of data types, SQLite is doing the work.

Looking at the Core Data Stack

The Core Data stack is a set of three objects that work together to provide functionality. They are as follows:

  • Managed Object Model. This is what you saw built graphically in Chapter 8. It’s very similar to what is often referred to as a database schema. (A schema is described in a formal language rather than graphically.) Remember that relationships are explicitly defined in a Core Data data model whereas in SQLite (and in SQL in general) the relationships are implemented in the WHERE clauses that you write.
  • Persistent Store Coordinator. Each SQLite table is usually represented as a persistent store in Core Data. This one-to-one correspondence of persistent store and database table is sufficient in most cases. However, you can have multiple persistent stores to improve performance or provide other optimizations. As far as the Core Data stack is concerned, one of the three key elements is a persistent store coordinator which coordinates all of the persistent stores for a given Core Data app.

    In most cases, the persistent store coordinator handles a single persistent store. However, the full name (persistent store coordinator) is still used because in more complex solutions the persistent store coordinator does actually manage several persistent stores. It is the persistent store coordinator and its persistent stores that do the transformation from the flat SQLite database file to the objects that you work with in your Core Data app. Accordingly, there are options you use when you create a persistent store that specify what the underlying data is (XML on OS X, SQLite on any of the platforms, in-memory stores, and others that may be created in the future).

    The defined store types are

    • NSSQLLiteStoreType
    • NSXMLStoreType (OS X)
    • NSBinaryStoreType (OS X)
    • NSInMemoryStoreType (OS X)
  • Managed Object Context. A managed object context is like a scratch pad: it contains data that has been retrieved from a persistent store and that has (perhaps) been modified by your app. When you are finished with modifications, you save the managed object context. If you want to cancel the operation, you simply destroy the managed object context.

The Core Data stack consists of these three objects, and they relate to one another to create a single entity.

Fetching Data to the Core Data Stack

Fetch requests can be created in Xcode Core Data model editor or in your code. They retrieve data from a persistent store (through a persistent store coordinator) and place it in a managed object context. Fetch requests are not part of the Core Data stack, and that fact is reflected in the standard architecture for Core Data (described in the following section).

Structuring a Core Data App

The basic Core Data stack (persistent store coordinator, data model, and managed object context) typically is placed in a location that is available throughout the app. The most common case (used in Master-Detail Application and Single View Application templates built into Xcode) places the Core Data stack in AppDelegate. AppDelegate typically creates views and other objects within the app. If they will need parts of the Core Data stack, AppDelegate passes them down to the views either when they are created or when AppDelegate is managing them after they have been created by others.

Passing a Managed Object Context to a View Controller in iOS

Here is how the Master-Detail Application template for iOS passes the managed object context to the view. (As is the case with Apple’s code samples and much new code that’s written today, this is Swift code.)

func application(application: UIApplication,
  didFinishLaunchingWithOptions
    launchOptions: [NSObject: AnyObject]?) -> Bool {

   // Override point for customization after application launch.
    let splitViewController = self.window!.rootViewController
      as! UISplitViewController
    let navigationController =
      splitViewController.viewControllers[splitViewController.viewControllers.count-1]
      as! UINavigationController
    navigationController.topViewController!.navigationItem.leftBarButtonItem =
      splitViewController.displayModeButtonItem()
    splitViewController.delegate = self

    let masterNavigationController = splitViewController.viewControllers[0]
      as! UINavigationController
    let controller = masterNavigationController.topViewController
      as! MasterViewController
    controller.managedObjectContext = self.managedObjectContext
    return true
  }

The views are created from a storyboard, and this code starts from the basic window and steps down until it finds the navigation controller at the left of the split view controller. From there, it steps down to the MasterViewController inside the navigation controller. Having gotten that controller, it then sets the managedObjectContext property of MasterViewController to the managedObjectContext created in the Core Data stack in AppDelegate (that is the line of code shown in bold). This is the standard way of doing this.

You can also get to the Core Data stack by finding the app delegate and then accessing one of the stack objects from inside the AppDelegate. This breaks the idea of encapsulation because you’re looking inside the app delegate. However, you’ll find some sample code that does this in various places, and a (weak) argument can be made for doing it this way if you only rarely—like once—need to access the stack. Here’s the code for this other way of getting to the stack.

let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
// use appDelegate.managedObjectContext or some other stack property

Setting Up the Core Data Stack in AppDelegate for iOS

This code is from the Single View Application template that’s built into Xcode. It consists of lazy var declarations for the following:

  • applicationDocumentsDirectory. This is the directory in which your data model will be placed inside your app. It’s just a utility function.
  • managedObjectModel
  • persistentStoreCoordinator
  • managedObjectContext

    By using lazy vars, the initialization code only runs when you actually need it. Thus, this code in the template would never run unless you use Core Data. The comments from the template code are included here.

Creating applicationDocumentsDirectory in iOS

This code uses the default file manager to find the document directory for your app. If you want to change the location of your data model’s directory, change it here in the code shown in bold. Either use a different directory or create one of your own (and be careful when you’re not using the default directory).

lazy var applicationDocumentsDirectory: NSURL = {
  // The directory the application uses to store the Core Data store file.
  // This code uses a directory named "com.champlainarts.SingleViewCoreDataSwift"
  // in the application’s documents Application Support directory.

  let urls = NSFileManager.defaultManager().
    URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)

    return urls[urls.count-1]
}()

Creating managedObjectModel in iOS

Here the managedObjectModel code is created as needed. The line shown in bold is created when you use the template. If you change your project’s name, change this line of code. Also note that, by default, the Core Data model is stored in the app bundle. The xcdatamodeld file that you build with Xcode Core Data model editor is compiled into a momd file during the build process.

lazy var managedObjectModel: NSManagedObjectModel = {
  // The managed object model for the application. This property is not optional.
  // It is a fatal error for the application not to be able to find
  // and load its model.

  let modelURL = NSBundle.mainBundle().URLForResource
    ("SingleViewCoreDataSwift", withExtension: "momd")!
  return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

Creating persistentStoreCoordinator in iOS

This code creates a persistent store coordinator based on your managed object model. The second line shown in bold is created based on your project name, and it contains the location of the SQLite database file. You normally don’t move this file, but this is another place where you might have to change the file name if you have changed the project name.

Note that in using the data model, if self.managedObjectModel does not exist yet, it will be created after the reference here.

It’s also worth pointing out the line where the SQLiteStoreStype is chosen for the new persistent store. It’s shown in the third bold line.

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
  // The persistent store coordinator for the application. This implementation
  //  creates and returns a coordinator, having added the store for the
  // application to it. This property is optional since there are
  // legitimate error conditions that could cause the creation of the
  // store to fail.

  // Create the coordinator and store

  let coordinator = NSPersistentStoreCoordinator
    (managedObjectModel: self.managedObjectModel)

  let url = self.applicationDocumentsDirectory.
    URLByAppendingPathComponent("SingleViewCoreData.sqlite")

  var failureReason = "There was an error creating or loading the
    application’s saved data."

  do {
    try coordinator.addPersistentStoreWithType
      (NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
    } catch {

    // Report any error we got.

    var dict = [String: AnyObject]()

    dict[NSLocalizedDescriptionKey] =
      "Failed to initialize the application’s saved data"
    dict[NSLocalizedFailureReasonErrorKey] = failureReason
    dict[NSUnderlyingErrorKey] = error as NSError

    let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN",
                                 code: 9999,
                             userInfo: dict)

    // Replace this with code to handle the error appropriately.
    // abort() causes the application to generate a crash log
    // and terminate. You should not use this function in a
    // shipping application, although it may be useful during development.

    NSLog("Unresolved error (wrappedError),
      (wrappedError.userInfo)")

    abort()
  }

  return coordinator
}()

If you are not familiar with Swift 2, you may not have seen the do/try/catch block. That is used increasingly in modern Swift code, so this code can serve as a template for other do/try/catch code you may write. The heart of it is in the catch section. The important part of that code is the following:

  1. Catch the error.
  2. Create an empty dictionary (var dict in this case).
  3. Populate the dictionary. This code will be customized for your purposes.
  4. Create a new NSError instance with the domain, code, and dictionary that you created in items 2 and 3.
  5. Report the error and dictionary using NSLog.

Creating managedObjectContext in iOS

Finally, the managed object context is created. (Note that because of lazy initialization, “finally” may not be accurate because the sequence of creating the Core Data stack components varies depending on which one is the first one accessed.)

lazy var managedObjectContext: NSManagedObjectContext = {
  // Returns the managed object context for the application
  // (which is already bound to the persistent store coordinator
  // for the application.) This property is optional since there
  // are legitimate error conditions that could cause the creation
  // of the context to fail.

  let coordinator = self.persistentStoreCoordinator
  var managedObjectContext = NSManagedObjectContext
    (concurrencyType: .MainQueueConcurrencyType)
  managedObjectContext.persistentStoreCoordinator =
    coordinator
  return managedObjectContext
}()

Setting Up the Core Data Stack in AppDelegate for OS X

This code is from the Cocoa Application for OS X template that’s built into Xcode. It consists of lazy var declarations for the following:

  • applicationDocumentsDirectory. This is the directory in which your data model will be placed inside your app.
  • managedObjectModel
  • persistentStoreCoordinator
  • managedObjectContext

By using lazy vars, the initialization code only runs when you actually need it. Thus, this code in the template would never run unless you use Core Data. The comments from the template code are included here.

Creating applicationDocumentsDirectory in OS X

This code differs from iOS to reflect the fact that the file structures differ. Its purpose is the same. The code shown in bold is created from your settings when you set up the project. If you change your developer ID or project name, you may have to change this.

lazy var applicationDocumentsDirectory: NSURL = {
  // The directory the application uses to store the Core Data
  // store file. This code uses a directory named
  // "com.champlainarts.OSXProjectSwift" in the user’s Application Support directory.

  let urls = NSFileManager.defaultManager().
    URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask)

  let appSupportURL = urls[urls.count - 1]

  return appSupportURL.URLByAppendingPathComponent
    ("com.champlainarts.OSXProjectSwift")
}()

Creating managedObjectModel in OS X

The code is the same as it is for iOS except for the name of the project. The code that is shown in bold for iOS would change for OS X to this (assuming your project name is appropriate).

let modelURL = NSBundle.mainBundle().URLForResource
  ("OSXProjectSwift", withExtension: "momd")!

Creating persistentStoreCoordinator in OS X

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
  // The persistent store coordinator for the application. This
  // implementation creates and returns a coordinator, having added the
  // store for the application to it. (The directory for the store
  // is created, if necessary.) This property is optional since
  // there are legitimate error conditions that could cause the
  // creation of the store to fail.

  let fileManager = NSFileManager.defaultManager()
  var failError: NSError? = nil
  var shouldFail = false
  var failureReason = "There was an error creating or loading
    the application’s saved data."

  // Make sure the application files directory is there
  do {
    let properties = try
      self.applicationDocumentsDirectory.resourceValuesForKeys([NSURLIsDirectoryKey])
      if !properties[NSURLIsDirectoryKey]!.boolValue {
        failureReason = "Expected a folder to store application data,
          found a file (self.applicationDocumentsDirectory.path)."
      shouldFail = true
      }
    } catch  {
      let nserror = error as NSError
      if nserror.code == NSFileReadNoSuchFileError {
      do {
                  try fileManager.createDirectoryAtPath(self.applicationDocumentsDirectory.path!, withIntermediateDirectories: true, attributes: nil)
              } catch {
                  failError = nserror
              }
          } else {
              failError = nserror
          }
      }

      // Create the coordinator and store
      var coordinator: NSPersistentStoreCoordinator? = nil
      if failError == nil {
          coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
          let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("CocoaAppCD.storedata")
          do {
              try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: nil)
          } catch {
              failError = error as NSError
          }
      }

      if shouldFail || (failError != nil) {
          // Report any error we got.
          var dict = [String: AnyObject]()
          dict[NSLocalizedDescriptionKey] = "Failed to initialize the application’s saved data"
          dict[NSLocalizedFailureReasonErrorKey] = failureReason
          if failError != nil {
              dict[NSUnderlyingErrorKey] = failError
          }
          let error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
          NSApplication.sharedApplication().presentError(error)
          abort()
      } else {
          return coordinator!
      }
  }()

Creating managedObjectContext in OS X

This code is the same as in iOS.

Creating a Fetch Request in iOS

In iOS, the standard practice is to create the Core Data stack in the app delegate as shown previously in this chapter in “Structuring a Core Data App.: In addition to the Core Data stack, you typically use fetch requests to fetch data from the persistent store into the managed object context. (On OS X, you use binding instead of view controllers and fetch requests.)

This code is fairly common. Here, it is used to fetch all entities with a given name (Event). The entity description is retrieved from the managed object context (the line is shown in bold) and the fetched results controller is created with a reference to that managed object context. A backing variable for the fetchedResultsController is created with the name _fetchedResultsController. This design pattern is frequently use: if the backing variable (starting with the underscore) exists, it is returned on request. If it does not exist, the fetched results controller is created and the underscore backing variable is set to it for the next time it’s needed.

var fetchedResultsController: NSFetchedResultsController {
  if _fetchedResultsController != nil {
    return _fetchedResultsController!
  }

  let fetchRequest = NSFetchRequest()
  // Edit the entity name as appropriate.
  let entity = NSEntityDescription.entityForName("Event",
    inManagedObjectContext: self.managedObjectContext!)
  fetchRequest.entity = entity

  // Set the batch size to a suitable number.
  fetchRequest.fetchBatchSize = 20

  // Edit the sort key as appropriate.
  let sortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)

  fetchRequest.sortDescriptors = [sortDescriptor]

  // Edit the section name key path and cache name if appropriate.
  // nil for section name key path means "no sections".

  let aFetchedResultsController = NSFetchedResultsController(
            fetchRequest: fetchRequest,
    managedObjectContext: self.managedObjectContext!,
      sectionNameKeyPath: nil,
               cacheName: "Master")
  aFetchedResultsController.delegate = self
  _fetchedResultsController = aFetchedResultsController

  do {
    try _fetchedResultsController!.performFetch()
  } catch {
    // Replace this implementation with code to handle the
    // error appropriately.
    // abort() causes the application to generate a crash log
    // and terminate. You should not use this function in a
    // shipping application, although it may be useful during development.

    print("Unresolved error (error), (error.userInfo)")
    abort()
  }

  return _fetchedResultsController!
}

var _fetchedResultsController: NSFetchedResultsController? = nil

If you have created a fetch request in your data model as described in Chapter 8, you can use it to create a fetchedResultsController.

Saving the Managed Object Context

Although this is basically the same in iOS and OS X, there are some minor differences.

Saving in iOS

The last part of Core Data in the app delegate is the utility code to save the context and its changes. If you don’t save the managed object context, the changes are gone.

func saveContext () {
  if managedObjectContext.hasChanges {

    do {
      try managedObjectContext.save()
    } catch {

      // Replace this implementation with code to handle the error appropriately.
      // abort() causes the application to generate a crash log and terminate. You
      // should not use this function in a shipping application, although it
      // may be useful during development.

      let nserror = error as NSError
      NSLog("Unresolved error (nserror), (nserror.userInfo)")
      abort()
    }
}

This is one of the main reasons for passing the managed object context to views that are created or managed by the app delegate (see the section “Passing a Managed Object Context to a View Controller in iOS”). If the view has the managed object context, as it is processing changes to the view, it can save those changes with managedObjectContext.save.

Here is the standard code from a view controller that can save data.

do {
  try context.save()
  } catch {
    // Replace this implementation with code to handle the error
    // appropriately.
    // abort() causes the application to generate a crash log
    // and terminate. You should not use this function in a
    // shipping application, although it may be useful during development.

    print("Unresolved error (error), (error.userInfo)")
    abort()
  }
}

Saving in OS X

With the menu bar and its commands in OS X, you often are using a Save action to save data. Here is a typical saveAction function from OS X.

@IBAction func saveAction(sender: AnyObject!) {
  // Performs the save action for the application, which is to send the save: message
  // to the application’s managed object context. Any encountered errors are presented
  // to the user.

  if !managedObjectContext.commitEditing() {
    NSLog("(NSStringFromClass(self.dynamicType))
      unable to commit editing before saving")
    }

    if managedObjectContext.hasChanges {
      do {
        try managedObjectContext.save()
      } catch {
        let nserror = error as NSError
        NSApplication.sharedApplication().presentError(nserror)
      }
    }
  }

Working with NSManagedObject

In any app that uses Core Data, you’ll need a Core Data stack, and you create it pretty much the same way each time except that you do customize the name of your project. (If you’re building your app from one of the built-in Xcode templates, there may be a Core Data check box you can use to automatically insert the Core Data stack code as well as your project name.)

But what about your data? That’s going to be managed by your Core Data stack, but surely it requires special coding. The fact is that, as is often the case with Core Data, the SQLite syntax is handled for you behind the scenes. You already have a data model (either from the template as-is or with your modifications) and if you don’t, you need to create a data model using File image New image File.

Image Note  In OS X, view controllers are not generally used; instead, bindings are used. That topic is covered in developer.apple.com.

Each entity in your data model will be transformed into an instance of a class at runtime. Each of those instances is an instance of NSManagedObject or a descendant thereof. This section shows you the basics.

The examples in this section use the same two entities that have been used previously in this book: User and Score. Figure 9-1 shows them in the Xcode Core Data model editor graph view.

9781484217658_Fig09-01.jpg

Figure 9-1. User and Score entities in a data model

Creating a New NSManagedObject Instance

There are several ways to create new Core Data instances. One of the most common is found in the Master-Detail Application template for iOS. Here’s the code that is used there. It is connected to a + in the  MasterViewController view. Users can tap + to create a new object.

func insertNewObject(sender: AnyObject) {
  let context = self.fetchedResultsController.managedObjectContext
  let entity = self.fetchedResultsController.fetchRequest.entity!

  let newManagedObject =
    NSEntityDescription.insertNewObjectForEntityForName(entity.name!,
    inManagedObjectContext: context)

  do {
    try context.save()
  } catch {
    abort()
  }
}

You use this code (or code very much like it) whenever you create a new NSManagedObject. The beginning of this code just locates the managed object context. It might be a property in the class you’re working with such as a fetchedResultsController. If it isn’t you may need to add a local property which is created (or passed through) when your class is instantiated or when the instance is loaded from a storyboard.

Next, you create an entity description, a subclass of NSEntityDescription. This encapsulates the entity information that you manage in your data model. In the code shown here, the entity description (called entity) is retrieved from a fetched results controller.

The third line of the code actually creates a new instance called newManagedObject. That line of code is worth examining in detail. It’s really quite simple, but it’s the heart of Core Data.

let newManagedObject =
    NSEntityDescription.insertNewObjectForEntityForName(entity.name!,
    inManagedObjectContext: context)

You use a class method of NSEntityDescription to create the new object—insertNewObjectForEntityForName. You need the name of the new object to be created and you need the managed object context into which to put it.

If you know the name of the object you want to create, you can omit the line creating entity (the second line of this code) and change this line of code to refer to it by name as in the following snippet.

let newManagedObject =
    NSEntityDescription.insertNewObjectForEntityForName("User",
    inManagedObjectContext: context)

Obviously, this code is less reusable, but it works.

After you have created that new managed object you save the managed object context into which you inserted it.

do {
    try context.save()
  } catch {
    abort()
  }
}

As noted in comments through the template code as well as elsewhere in this book, don’t use abort() in a shipping app. Instead, catch the error and log it, let the user know that there’s a problem (if the user can do something about it), or just fix the problem in your code.

That’s all it takes to create a new managed object.

If you want to set a value for an attribute defined for the entity in your data model, you can use key-value coding to do so with a line of code such as the following:

newManagedObject.setValue("New User", forKey: "name")

If the value to which you set the property is invalid, the save of the managed object context will fail. This will happen particularly if you’ve declared validation rules in the Xcode Data Model editor. Until you shake down the validation rules, you may have to deal with errors appropriately. (And, of course, if you are allowing user input, a whole host of user-generated errors may occur.)

Image Tip  If you really want to gain an appreciation of Core Data, work through the SQLite syntax that must be generated behind the scenes to implement the code shown here. It definitely is being executed, but you don’t have to type it in.

Working with a Subclass of NSManagedObject

You can create a subclass of NSManagedObject instead of using an instance of NSManagedObject itself. If you create a subclass (the process is described next), the chief benefit is that instead of using key-value coding, you can set a value for newManagedObject using code such as the following:

newManagedObject.name = "New User"

Creating a new subclass of NSManagedObject is easy with Xcode Core Data model editor. Here are the steps involved. Begin with your data model open as shown in Figure 9-1. (It doesn’t matter if you’re looking at the graph or table view.) Choose Editor  image Create NSManagedObject Subclass to open the window shown in Figure 9-2. Select the data model you want to use as shown in Figure 9-2. (Typically there’s only one. There may be several if you have been modifying your data model.)

9781484217658_Fig09-02.jpg

Figure 9-2. Select your data model

After you click Next, choose the entity or entities you want to subclass (see Figure 9-3). By default, the entity or entities that you have selected in the graph or table view (as shown in Figure 9-1) are selected here. You don’t have to subclass everything. Sometimes, you choose to subclass the more complex entities and leave the others as NSManagedObject instances.

9781484217658_Fig09-03.jpg

Figure 9-3. Choose the entities to subclass

Click Next and choose where to save your new files as shown in Figure 9-4. Also choose the language you want for the subclass files. (You can mix and match Swift and Objective-C.)

9781484217658_Fig09-04.jpg

Figure 9-4. Choose where to save the subclass files and what language you want to use

You should double-check the group (for the Navigator) and the target, but usually they’re correct. The option for scalar properties requires a little explanation. By default, your entity attributes are converted into Swift or Objective-C properties using the native Cocoa or Cocoa Touch types. Thus, a Double is converted to NSNumber. NSNumber is a much more powerful construct than Double (for one thing, it’s a class). If you’re working a lot with such a property, sometimes the power of NSNumber gets in the way. Choosing to use scalar types will use the basic platform (non-object) types (such as Double) which may make your code simpler.

If your project is basically written in Swift and you choose to create your subclass in Objective-C, you may be asked if you want to create a bridging header between the two languages as shown in Figure 9-5. Yes, you do want to do this.

9781484217658_Fig09-05.jpg

Figure 9-5. You can choose to create a bridging header

In a mixed-language project, don’t worry if you’re not asked about a bridging header. It only need to be created once, so after the first time, you won’t be asked again.

The bridging header is created for you in the Build Settings of your project as shown in Figure 9-6. You don’t need to do anything further.

9781484217658_Fig09-06.jpg

Figure 9-6. Building settings with a bridging header

If you’re creating a Swift subclass, Xcode will create two files for each entity you have selected. The first is the basic file for the class (User in this case): it’s empty, and looks as follows:

import Foundation
import CoreData

class User: NSManagedObject {

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

}

It will be named User.swift. As the comment in the code indicates, you can add any code that you want to this new class that you’ve created.

The companion file that Xcode creates for you is a class extension. (A Swift class extension is like an Objective-C category but without a name.) Its name will be in the following form:

User+CoreDataProperties.swift

The contents of the file will be as follows:

import Foundation
import CoreData

extension User {

    @NSManaged var name: String?
    @NSManaged var email: String?
    @NSManaged var scores: NSManagedObject?
}

At runtime, the extension is merged with the basic class, so you’re able to access the name property for an instance of User by writing

myName.name = "test"

That’s all it takes to create an NSManagedObject subclass.

Image Note  To see how to use your subclasses, see Chapter 12.

Summary

This chapter shows you how to work with SQLite/Core Data on OS X and iOS using Swift—the more modern of languages for Cocoa and Cocoa Touch. There is still plenty of Objective-C code around, and Chapter 10 shows that code.

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

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