CoreDataStack

  • NSManagedOjectModel
  • NSPersistentStore
  • NSPersistentStoreCoordinator
  • NSManagedObjectContext
  • NSPersistentContainer
  • SampleCode

NSManagedObjectModel

  • The NSManagedObjectModel represents each object type in your app’s data model, the properties they can have, and the relationships between them. Other parts of the Core Data stack use the model to create objects, store properties and save data.
  • [Note]
    The visual editor creates and edits an xcdatamodel file. There’s a special compiler, momc, that compiles the model file into a set of files in a momd folder.
    Just as your Swift code is compiled and optimized so it can run on a device, the compiled model can be accessed efficiently at runtime. Core Data uses the compiled contents of the momd folder to initialize an NSManagedObjectModel at runtime.

NSPersistentStore

NSPersistentStore reads and writes data to whichever storage method you’ve decided to use.

Core Data provides four types of NSPersistentStore out of the box: three atomic and one non-atomic.

[Note]

An atomic persistent store needs to be completely deserialized and loaded into memory before you can make any read or write operations. In contrast, a non-atomic persistent store can load chunks of itself onto memory as needed.

CoreDataStoreType

NSQLiteStoreType

NSQLiteStoreType is backed by an SQLite database. It’s the only non-atomic store type Core Data supports out of the box, giving it a lightweight and efficient memory footprint. This makes it the best choice for most iOS projects. Xcode’s Core Data template uses this store type by default.

NSXMLStoreType

NSXMLStoreType is backed by an XML file, making it the most human-readable of all the store types. This store type is atomic, so it can have a large memory footprint. NSXMLStoreType is only available on OS X.

NSBinaryStoreType

NSBinaryStoreType is backed by a binary data file. Like NSXMLStoreType, it’s also an atomic store, so the entire binary file must be loaded onto memory before you can do anything with it. You’ll rarely find this type of persistent store in real-world applications.

NSInMemoryStoreType

NSInMemoryStoreType is the in-memory persistent store type. In a way, this store type is not really persistent. Terminate the app or turn off your phone, and the data stored in an in-memory store type disappears into thin air. Although this may seem to defeat the purpose of Core Data, in-memory persistent stores can be helpful for unit testing and some types of caching.


NSPersistentStoreCoordinator

NSPersistentStoreCoordinator is the bridge between the managed object model and the persistent store. It’s responsible for using the model and the persistent stores to do most of the hard work in Core Data. It understands the NSManagedObjectModel and knows how to send information to, and fetch information from, the NSPersistentStore.

NSPersistentStoreCoordinator also hides the implementation details of how your persistent store or stores are configured. This is useful for two reasons:

  1. NSManagedObjectContext (coming next!) doesn’t have to know if it’s saving to an SQLite database, XML file or even a custom incremental store.
  2. If you have multiple persistent stores, the persistent store coordinator presents a unified interface to the managed context. As far as the managed context is concerned, it always interacts with a single, aggregate persistent store.

NSManagedObjectContext

  • A context is an in-memory scratchpad for working with your managed objects.
  • You do all of the work with your Core Data objects within a managed object context.
  • Any changes you make won’t affect the underlying data on disk until you call save( ) on the context.
  • The context manages the lifecycle of the objects it creates or fetches. This lifecycle management includes powerful features such as faulting, inverse relationship handling and validation.
  • A managed object cannot exist without an associated context. In fact, a managed object and its context are so tightly coupled that every managed object keeps a reference to its context, which can be accessed like so:
    managedContext
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    > - Contexts are very territorial; once a managed object has associated with a particular context, it will remain associated with the same context for the duration of its lifecycle.
    > - An application can use more than one context — most non-trivial Core Data applications fall into this category. Since a context is an in-memory scratch pad for what’s on disk, you can actually load the same Core Data object onto two different contexts simultaneously.
    > - A context is not thread-safe. The same goes for a managed object: You can only interact with contexts and managed objects on the same thread in which they were created.

    ------

    ### NSPersistentContainer

    > The name of this class is NSPersistentContainer and as its name implies, it’s a container that holds everything together. Instead of wasting your time writing boilerplate code to wire up all four stack components together, you can simply initialize an NSPersistentContainer, load its persistent stores, and you’re good to go.


    ### Sample Code

    ```swift
    import Foundation
    import CoreData

    class CoreDataStack {

    private let modelName: String

    init(modelName: String) {

    self.modelName = modelName

    }

    lazy var managedContext: NSManagedObjectContext = {

    return self.storeContainer.viewContext

    }()



    private lazy var storeContainer: NSPersistentContainer = {

    let container = NSPersistentContainer(name: self.modelName)

    container.loadPersistentStores { (storeDescription, error) in
    if let error = error as NSError? {
    print("Unresolved error \(error), \(error.userInfo)")
    }
    }
    return container
    }()

    func saveContext () {

    guard managedContext.hasChanges else { return }

    do {
    try managedContext.save()
    } catch let nserror as NSError {
    print("Unresolved error \(nserror), \(nserror.userInfo)")
    }
    }
    }