Slide 1

Slide 1 text

Core Data: It’s Not Dead Yet Abizer Nasir | @abizern | abizern.org

Slide 2

Slide 2 text

In this talk I am going to remind you why Core Data is still relevant.

Slide 3

Slide 3 text

What is Core Data → It is the Model layer for your application. → It is not just the persistence to disk, but also the the data objects. → Most of the time we concentrate on the objects, and think of saving to disk as secondary.

Slide 4

Slide 4 text

Some Reasons People Don’t Use Core Data? → It’s a very big SDK which is hard to understand. → The team has different levels of Core Data experience. → Bugs and performance problems are hard to find and fix. → They’ve been burned with it before.

Slide 5

Slide 5 text

Alternatives To Core Data → UserDefaults (Yes - I’ve seen this) ugh → NSCoding Not best for dynamic data → Magical Record Active Record on top of Core Data

Slide 6

Slide 6 text

Alternatives - Realm → Open source → Cross Platform → Fast - Multithreaded → Easy to setup and use → Many plugins are available

Slide 7

Slide 7 text

But Realm isn’t Core Data

Slide 8

Slide 8 text

Core Data is large because it is powerful and flexible. You don’t have to use everything that it comes with.

Slide 9

Slide 9 text

Core Data Is Part Of The System → Uses the latest available Swift / Objective-C syntax. → Works across all platforms. → Manages memory pressure → NSFetchedResultsController, for driving Table or Collection Views. → UIManagedDocument for document based

Slide 10

Slide 10 text

Core Data Gives This For Free → Memory management with faulting. → Change Notifications. → Able to handle large datasets. → Undo / Redo. → Object Validation. → Management of the Object Graph.

Slide 11

Slide 11 text

The Core Data Stack

Slide 12

Slide 12 text

Not As Scary As It Looks.

Slide 13

Slide 13 text

NSPersistentStore This is where the data is persisted. Usually the an SQLite store on disk, but can be memory.

Slide 14

Slide 14 text

NSManagedObjectModel Description of the Entities; their properties and their relationships.

Slide 15

Slide 15 text

NSPersistentStoreCoordinator Mediates between the data

Slide 16

Slide 16 text

NSManagedObjectContext This is what we mainly care about. Most operations on model objects will occur in a moc.

Slide 17

Slide 17 text

One Way To Set Up The Stack func initializeCoreDataStack() { guard let modelURL = NSBundle.mainBundle().URLForResource("PPRecipes", withExtension: "momd") else { fatalError("Failed to locate DataModel.momd in app bundle") } guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else { fatalError("Failed to initialize MOM") } let psc = NSPersistentStoreCoordinator(managedObjectModel: mom) let type = NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType mainContext = NSManagedObjectContext(concurrencyType: type) mainContext?.persistentStoreCoordinator = psc let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) dispatch_async(queue) { let fileManager = NSFileManager.defaultManager() guard let documentsURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first else { fatalError("Failed to resolve documents directory") } let storeURL = documentsURL.URLByAppendingPathComponent("PPRecipes.sqlite") do { try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil) } catch { fatalError("Failed to initialize PSC: \(error)") } self.populateTypeEntities() self.persistenceInitialized = true dispatch_sync(dispatch_get_main_queue()) { self.initializationComplete?() } } }

Slide 18

Slide 18 text

!

Slide 19

Slide 19 text

NSPersistentContainer → New, and simpler way of creating the Core Data Stack with sensible defaults. → Provides Convenience methods for dealing with multithreaded contexts. → Loads the stack asynchronously.

Slide 20

Slide 20 text

New way to set up the stack: lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "MyApp") container.loadPersistentStores) { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } // Stack ready to use. } return container }()

Slide 21

Slide 21 text

Managed Object Model → Model objects are subclasses on NSManagedObject. → Properties and relationships defined graphically.

Slide 22

Slide 22 text

Managed Object Model → Core Data is about Entities and relationships, don’t think of keys and joins. → Be careful with inheritance, it doesn’t do what you think it does; subclasses all share the same table. → Make sure relationships are double ended

Slide 23

Slide 23 text

Managed Objects → These are the actual data objects. → Managed by the Persistent Store Coordinator for putting them in a Managed Object Context or saving them to the Persistent Store. → Cannot be used across threads. → Use the objectID to recreate the object in other threads.

Slide 24

Slide 24 text

New Convenience methods Much nicer initialiser: public convenience init(context moc: NSManagedObjectContext) Nicer way to get a fetch request public class func fetchRequest() -> NSFetchRequest

Slide 25

Slide 25 text

Automatic Code Generation In the past, without generating a custom subclass, you needed to use Key-Value Coding: myObject.valueForKey("myProperty") Xcode 8 can now automatically generate the subclass and keep the files in Derived Data so it doesn’t appear in the source.

Slide 26

Slide 26 text

Class Definition → Select Class Definition and Xcode will generate the class and the category for the properties. → You don’t have to create any files.

Slide 27

Slide 27 text

Category Extension → You create the file which defines the class, with additional properties or methods. → Xcode generates the extension which has the properties and relationships defined in the editor.

Slide 28

Slide 28 text

Multi-threading with MOCs Managed Objects can only be accessed from the same queue as their managed context. The initialiser is explicit init(concurrencyType ct: NSManagedObjectContextConcurrencyType)

Slide 29

Slide 29 text

.mainQueueConcurrencyType → Runs on the main queue → Use objects from this type of managed object context in the UI. → NSPersistentContainer provides one with the viewContext parameter.

Slide 30

Slide 30 text

.privateQueueConcurrencyType → Runs on a background queue useful for performing background tasks such as importing data. → NSPersistentContainer provides one with the newBackgroundContext() method. → Better to pass a closure to the performBackgroundTask method, which runs the block on the correct queue.

Slide 31

Slide 31 text

Fetched Results → You get data into a managed object context with a fetch request. → Recently changed to have a generic type so no need to cast the results to the correct type.

Slide 32

Slide 32 text

Create the request let request: NSFetchRequest = Note.fetchRequest() let sortDescriptor = NSSortDescriptor(key: #keyPath(Note.title), ascending: true) let predicate = NSPredicate(format: "%K beginswith %@", #keyPath(Note.title), "2016") request.sortDescriptors = [sortDescriptor] request.predicate = predicate

Slide 33

Slide 33 text

Run the request var results: [Note] = [] do { results = try container.viewContext.fetch(request) } catch { print("\(error)") } // do something with results

Slide 34

Slide 34 text

NSFetchedResultsController → Really useful table view and collection data sources. → Handles sections, section names, number of items, identifying objects with index paths. → Listens to changes in the context.

Slide 35

Slide 35 text

Before The Changes Prepare the table view for changes in the datasource func controllerWillChangeContent( _ controller: NSFetchedResultsController) { tableview.beginUpdates() }

Slide 36

Slide 36 text

Manage The Changes Make the changes to the tableview. func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { switch type { case .insert: // Insert rows case .delete: // Delete rows case .move: // Move rows case .update: // Update these rows } }

Slide 37

Slide 37 text

After The Changes Finalize the changes. func controllerDidChangeContent( _ controller: NSFetchedResultsController) { tableview.endUpdates() }

Slide 38

Slide 38 text

Faulting → When you fetch a managed object the properties and relationships may not be populated until they are actually used. This is called “firing a fault” → It’s like a promise of data that is available when you need it.

Slide 39

Slide 39 text

“could not fulfill a fault” → Although it’s a major reason for Core Data’s performance, it sometimes leads to puzzling errors. → This error is generated when the faulted object is deleted by some other context. → More common than you would expect, unfortunately.

Slide 40

Slide 40 text

New - Query Generations You can pin the context to a generation of data. If a fault gets deleted, it is still available to the pinned context.

Slide 41

Slide 41 text

do { try container.viewContext.setQueryGenerationFrom(NSQueryGenerationToken.current) } catch { print("\(error)") } It’s now safe to fire a fault, the object and properties will still be available even if it has been deleted from the most current generation.

Slide 42

Slide 42 text

→ Any fetches will load the most recent version and pin it to the most current version. → As will save(), reset() or handling any merge notifications.

Slide 43

Slide 43 text

iCloud

Slide 44

Slide 44 text

! Okay - Core Data on iCloud is Dead !

Slide 45

Slide 45 text

→ Not mentioned in the WWDC talk - but it is in the release notes. → The Core Data iCloud methods have all been marked as deprecated, but they will be available for some time.

Slide 46

Slide 46 text

References

Slide 47

Slide 47 text

Core Data in Swift Marcus Zarra

Slide 48

Slide 48 text

Objc.io Core Data Florian Kugler & Daniel Eggert

Slide 49

Slide 49 text

Summary → Core Data is getting easier to use. → Better support for Swift. → I’m really excited to try the new capabilities, and I hope you are too.

Slide 50

Slide 50 text

Thank You Abizer Nasir | @abizern | abizern.org