Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A taste of Core Data #1

5bfb729f6ac07e17c2326a7335a3f3be?s=47 yageek
December 19, 2017

A taste of Core Data #1

From the trenches - Code location: https://github.com/yageek/a-taste-of-core-data

5bfb729f6ac07e17c2326a7335a3f3be?s=128

yageek

December 19, 2017
Tweet

Transcript

  1. © 2017 Yannick Heinrich. All Rights Reserved. A taste of

    CoreData #1 From the trenches
  2. What is CoreData? CoreData as a graph framework Add business

    semantics CoreData as a persistence framework Working with the data Plan
  3. What is CoreData?

  4. « Contrary to popular belief, Core Data is not an

    Object-Relational Mapper, but rather an object graph and persistence framework, capable of much more than the Active Record pattern alone is capable of. Using Core Data as an ORM necessarily limits the capabilities of Core Data and muddies its conceptual purity. But for many developers longing for the familiarity of an ORM, this trade-off is a deal at twice the price! » Mattt Thompson, @mattt, http://nshipster.com/core-data-libraries-and-utilities/ What is Core Data?
  5. Why CoreData? •Creates a graph of object that you would

    eventually persist in. •The model part of your MVC/MVVM •To persist your data also •Help to synchronise with backend services •Simplify UI design.
  6. Graph !!= ORM B#1 C#1 C#2 C#3 A#1 A#2 B#2

    B#3 ID Prop 1 Prop 2 Prop 3 #1 # # # #2 # # # #3 # # # #4 # # # A ID Prop 1 Prop 2 Prop 3 #1 # # # #2 # # # #3 # # # #4 # # # B ID Prop 1 Prop 2 Prop 3 #1 # # # #2 # # # #3 # # # #4 # # # C !!= Core Data ORM
  7. •Using an ORM/Relational Database involves mostly writing SQL statements that

    returns Record (Pure Value elements) from a sets of tables. •Using a graph involves looking for object instances (node) from a specific graph instance. Graph !!= ORM
  8. CoreData as a graph framework

  9. Graph semantics B#1 C#1 C#2 C#3 A#1 A#2 edge node

    graph instance B#1 C#1 C#2 C#3 A#1 A#2 B#2 B#3
  10. Core Data vs Graph B#1 C#1 C#2 C#3 A#1 A#2

    edge = relationship node = NSManagedObject graph instance = NSManagedObjectContext B#1 C#1 C#2 C#3 A#1 A#2 B#2 B#3
  11. CoreData view NSManagedObject NSManagedObjectContext #1 NSManagedObjectContext #2

  12. How do we create a graph ?

  13. Playground - Basic Initialisation Context is easy Let take a

    look at the documentation (concurrencyType will be explained in a next workshop): // Swift let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) // Objective-C NSManagedObjectContext * ctx = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSMainQueueConcurrencyType]; Using Code: Context initialisers
  14. Playground - Basic Initialisation Object (node) ? How do we

    create object and create relationships? Documentation? ??? Object initialisers
  15. Playground - Basic Initialisation Object (node) ? Some troubles? Other

    way?
  16. Playground - Entity Description NSEntityDescription Properties and documentation

  17. Dealing with different nodes In reality we deals with more

    complex graph that have different kind of nodes (aka. nodes with different properties) and that have interactions. Example: Boss #1 name: Javier Employee #2 name: Damien speciality: iOS Boss #2 name: Mathieu Boss #3 name: Samy Employee #2 name: Alberto speciality: iOS Employee #2 name: Elaine speciality: test Employee #2 name: Khali speciality: test underBosses(*) employees (*) boss (1) bosses (*)
  18. Playground - Multiple Descriptions Attributes and relationships Properties and documentation

  19. Playground - Multiple Descriptions Attributes and relationships usage // Attributes

    let nameAttr = NSAttributeDescription() nameAttr.name = "name" nameAttr.attributeType = .stringAttributeType nameAttr.defaultValue = "No Name" let specialityAttr = NSAttributeDescription() specialityAttr.name = "speciality" specialityAttr.attributeType = .stringAttributeType // Boss Description let bossDescription = NSEntityDescription() bossDescription.name = "Boss" // Employee Description let employeeDescription = NSEntityDescription() employeeDescription.name = "Employee" // Relationships let bossOneRel = NSRelationshipDescription() bossOneRel.name = "boss" bossOneRel.minCount = 0 bossOneRel.maxCount = 1 // To-One bossOneRel.destinationEntity = bossDescription let underBossesRel = NSRelationshipDescription() underBossesRel.name = "underBosses" underBossesRel.minCount = 0 underBossesRel.maxCount = 0 // To-Many underBossesRel.deleteRule = .nullifyDeleteRule underBossesRel.destinationEntity = bossDescription bossOneRel.inverseRelationship = underBossesRel underBossesRel.inverseRelationship = bossOneRel let bossesMulRel = NSRelationshipDescription() bossesMulRel.name = "bosses" bossesMulRel.minCount = 0 bossesMulRel.maxCount = 0 bossesMulRel.deleteRule = .nullifyDeleteRule bossesMulRel.destinationEntity = bossDescription let employeeMulRel = NSRelationshipDescription() employeeMulRel.name = "employees" employeeMulRel.minCount = 0 employeeMulRel.maxCount = 0 employeeMulRel.deleteRule = .nullifyDeleteRule employeeMulRel.destinationEntity = employeeDescription bossesMulRel.inverseRelationship = employeeMulRel employeeMulRel.inverseRelationship = bossesMulRel // Assign Relationships bossDescription.properties = [employeeMulRel, underBossesRel, bossOneRel, nameAttr]; employeeDescription.properties = [bossesMulRel, nameAttr, specialityAttr]; Alternatives to this boilerplate ? Keep track of evolution ?
  20. Playground - Multiple Descriptions with Model Managed Model tool NSManagedObjectModel

    Using the model tool Compilation Model (.xcdatamodel) Compiled Model (.momd)
  21. CoreData view NSManagedObject NSManagedObjectContext #1 NSManagedObjectContext #2 NSManagedObjectModel #1 NSEntityDescription

  22. It’s forbidden to transfer one NSManagedObject to another NSManagedObjectContext (will

    be explained in next session) Gold Rule
  23. Add business semantics

  24. What have we created until now? NSManagedObject NSManagedObject NSManagedObject NSManagedObject

    Empty NSManagedObjects graph with default value How to modify the attributes and relation ships we declared?
  25. /* Direct access to NSManagedObject private internal storage */ /*

    Does not triggers KVO updates */ - (void)setPrimitiveValue:(id)value forKey:(NSString *)key; - (id)primitiveValueForKey:(NSString *)key; /* Proxy methods to the upper ones */ /* Triggers KVO updates === KVC*/ - (id)valueForKey:(NSString *)key; - (void)setValue:(id)value forKey:(NSString *)key; - (NSMutableSet *)mutableSetValueForKey:(NSString *)key; Primitives to access elements Playground - Editing the node Every NSManagedObject is compatible with KVO/KVC
  26. •Modifying the properties and relationships is really verbose? •I have

    no real « type » information, just plain NSManagedObjectContext? •Any alternatives? Looks like boilerplate again Remember the documentation?
  27. •CoreData generates all properties and methods for you at runtime

    •KVC compliant (KVC programming guide -> Compliance Checklist) •@NSManaged looks like magic but it is not. Create subclasses! Playground - Editing the node - Subclasses @objc(Boss) public class Boss: NSManagedObject { @NSManaged var name: String? @NSManaged var bosses: Set<Boss>? @NSManaged var employees: Set<Employee> @NSManaged func addEmployeesObject(_ employee: Employee) } @objc(Employee) public class Employee: NSManagedObject { @NSManaged var name: String? @NSManaged var boss: Boss? }
  28. We can create, add, remove methods to existing classes at

    runtime. Dynamic Objc properties or methods Playground - Editing the node - Recap
  29. Operates at initialisation - initWithEntity:insertIntoManagedObjectContext: Discussion: NSManagedObject uses dynamic class

    generation to support the Objective-C 2 properties feature (see Declared Properties) by automatically creating a subclass of the class appropriate for entity. initWithEntity:insertIntoManagedObjectContext: therefore returns an instance of the appropriate class for entity. The dynamically-generated subclass will be based on the class specified by the entity, so specifying a custom class in your model will supersede the class passed to alloc. NSManagedObject documentation
  30. You can use custom class as properties by specifying a

    transformable attribute and one NSValueTransformer class that will marshal/unmarshall your class into a CoreData primitive type. Custom properties If no transformer is specified, the value transformer specified NSKeyedUnarchiveFromDataTransformerName is used (See Core Data Release Notes). In this case y ou only need to make your custom type conformed to NSCoding
  31. CoreData as a persistence framework

  32. Storing our graph instances to disk using CoreData. What we

    want to do?
  33. •Handling disk I/O •Validation of inputs •« Fine-tunable » regarding

    concurrency (Next session) •Performance (Next session) •Deal with migrations of data (Next session) What should persistence framework do?
  34. An abstract class that handles persistence to disk that comes

    with two flavours: •NSAtomicStore: each write implies re-written all the data from all the graphs. •NSIncrementalStore: each write implies writing only the changes. NSPersistentStore Atomic Incremental iOS Binary In-Memory, SQLite macOS Binary, XML In-Memory, SQLite
  35. You can implement you own store, but this topic is

    too complex for now. •NSAtomicStore: -> See Atomic Store Fundamentals •NSIncrementalStore: -> See Incremental Store Programming Guide and WWDC 201 1 Session 303 NSPersistentStore too deep for now
  36. Who will take care about the constraints specified in our

    model and validate the inputs before persisting? How to deal/synchronise different graph instances (aka MOC)? How to deal with different data location (aka different NSPersistentStore)? Consistency of data
  37. •MOC are bounded to it using the persistentStoreCoordinator •Validates changed

    and consistency according to the model provided at initialisation •Transmits changes from MOC to the stores once MOC called save() •Can Handle multiples NSPersistentStore instances NSPersistanceStoreCoordinator Playground - Store and Coordinators
  38. CoreData view NSEntityDescription NSManagedObject NSPersistentStore NSPersistentStoreCoordinator Model #2 Context #3

    Store #1 Store #2 Store #3 Context #2 Context #1 Coordinator #1 Coordinator #2 Model #1
  39. Working with the data

  40. Identifying a set of data is done using an NSFetchRequest

    object. Request can be executed either on the context or on the store coordinator •entityName -> Which kind of object to return •predicate -> Only includes object matching the predicate •fetchLimit -> Limit the number of object to fetch •fetchOffset -> Skip object in the returned set •fetchBatchSize -> Lazy load the object in batch •sortDescriptors -> Sort the set according to this descriptors Identifying data Playground - Basic requests
  41. We have also higher level requests: •NSBatchDeleteRequest •NSBatchUpdateRequest •NSPersistentStoreAsynchronousResult Batch

    updates
  42. If you have a graph with a huge number of

    elements and with a great depth, you probably do not want to load all the graph. By default, all children of a returned NSManagedObject are returned as Fault (lazy loaded object) CoreData will only load those children once you access to it. When you fetch in batch, the same principle is used. Faulting Playground - Faulting
  43. Questions?

  44. More Information Core Data Programming Guide NSManagedObjectContext/Object/Model/Store documentation Core Data

    Release Notes Predicate Programming Guide NSExpression documentation WWDC 2010 128 - Mastering Core Data Core Data Second Edition - Marcus Zara Core Data - Florian Kugler/Daniel Eggert objc.io Issue 4 - Core Data https://www.objc.io/issues/4-core-data/