What s New in Core Data?

Similar documents
What's New in Core Spotlight

Introduction to Siri Shortcuts

Using and Extending the Xcode Source Editor

Media and Gaming Accessibility

Seamless Linking to Your App

What s New in watchos

Modern User Interaction on ios

Mastering Drag and Drop

What s New in tvos #WWDC16. App Frameworks. Session 206. Hans Kim tvos Engineer

Data Delivery with Drag and Drop

What s New in CloudKit

What s New in imessage Apps

Core Data Best Practices

What s New in MapKit. App Frameworks #WWDC17. Fredrik Olsson

Extending Your Apps with SiriKit

Using Grouped Notifications

Automatic Strong Passwords and Security Code AutoFill

Introducing On Demand Resources

Writing Energy Efficient Apps

Introducing Password AutoFill for Apps

Your Apps and the Future of macos Security

What s New in Testing

Getting the Most Out of HealthKit

What s New in NSCollectionView Session 225

Introducing Search APIs

imessage Apps and Stickers, Part 2

What s New in Cocoa for macos

Introducing CloudKit. A how-to guide for icloud for your Apps. Frameworks #WWDC14. Session 208 Olivier Bonnet CloudKit Client Software

What s New in Xcode App Signing

Enhancing your apps for the next dimension of touch

CloudKit Tips And Tricks

What s New in SiriKit

Building for Voice with Siri Shortcuts

Cocoa Development Tips

Monetize and Promote Your App with iad

Advances in AVFoundation Playback

What s New in ARKit 2

Introducing MusicKit. Media #WWDC17. Tim Parthemore, MusicKit Services Joel Lopes Da Silva, ios Music

What s New in Cocoa. App Frameworks #WWDC17. Ali Ozer Daphne Larose

Enabling Your App for CarPlay

What s New in tvos 12

Core ML in Depth. System Frameworks #WWDC17. Krishna Sridhar, Core ML Zach Nation, Core ML

Implementing UI Designs in Interface Builder

Understanding Undefined Behavior

Touch Bar Fundamentals

What s New in SpriteKit

Vision Framework. Building on Core ML. Media #WWDC17. Brett Keating, Apple Manager Frank Doepke, He who wires things together

Finding Bugs Using Xcode Runtime Tools

What s New in Notifications

What s New in HomeKit

Use the API or contact customer service to provide us with the following: General ios Android App Name (friendly one-word name)

Leveraging Touch Input on ios

Localizing with Xcode 9

What s New in Audio. Media #WWDC17. Akshatha Nagesh, AudioEngine-eer Béla Balázs, Audio Artisan Torrey Holbrook Walker, Audio/MIDI Black Ops

Engineering for Testability

Accessibility on ios. Developing for everyone. Frameworks #WWDC14. Session 210 Clare Kasemset ios Accessibility

Integrating Apps and Content with AR Quick Look

What s New in Device Configuration, Deployment, and Management

Swift API Design Guidelines

Introducing the Modern WebKit API

Introducing the Photos Frameworks

Your Apps and Evolving Network Security Standards

Introducing Metal 2. Graphics and Games #WWDC17. Michal Valient, GPU Software Engineer Richard Schreyer, GPU Software Engineer

Thread Sanitizer and Static Analysis

Building Faster in Xcode

Quick Interaction Techniques for watchos

Creating Great App Previews

Mastering UIKit on tvos

Announcements. Today s Topics

Building Better Apps with Value Types in Swift Session 414

Building Watch Apps #WWDC15. Featured. Session 108. Neil Desai watchos Engineer

Building Visually Rich User Experiences

What s New in Foundation for Swift Session 207

Getting Started with CareKit

Advanced Scrollviews and Touch Handling Techniques

Managing Documents In Your ios Apps

ios Configuration and APIs for Kiosk and Assessment Apps

Advanced Notifications

What's New in UIKit Dynamics and Visual Effects Session 229

WatchKit In-Depth, Part 2

Creating Complications with ClockKit Session 209

Building Apps with Dynamic Type

What s New in Energy Debugging

Creating Extensions for Safari

CarPlay Audio and Navigation Apps

Settings. Mobile Application Development in ios School of EECS Washington State University Instructor: Larry Holder

New Ways to Work with Workouts

Designing for Apple Watch

CS 371L - Mobile Computing (ios) Dr. William C. Bulko. CS 371L Mobile Computing (ios) Introduction

What s New in Core Location

Getting the Most out of Playgrounds in Xcode

Multitasking Support on the ios Platform

Getting Published in Apple News

App Extension Best Practices

ios 9 Day by Day Also by shinobicontrols This version was published Scott Logic Ltd

Advances in TVMLKit. App Frameworks #WWDC17. Trevor Cortez, Localization Engineer Parry Panesar, tvos Engineer Jeremy Foo, tvos Engineer

What s New in LLDB. Debug your way to fame and glory #WWDC15. Developer Tools. Session 402

ITP 342 Mobile App Development. Data Persistence

User Interfaces. Lecture 15. Application Programming on Mac OS. Hamza Bennani September 4, 2018

Mysteries of Auto Layout, Part 1

Transcription:

Session App Frameworks #WWDC17 What s New in Core? Persisting since 2004 210 Melissa Turner, Core Engineer Rishi Verma, Core Engineer 2017 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

Roadmap Core Spotlight integration New indexing APIs Persistent history tracking

Alphonse Says Hi

CoreSpotlight

What is Spotlight Original search API on macos Document-centric Search results identify document Not location in document Not ideal for databases

What is Core Spotlight Original search tool on ios base-friendly Spotlight API Search for content in apps Allows deep linking

What is Core Spotlight NEW Original search tool on ios base-friendly Spotlight API Search for content in apps Allows deep linking Ships on Mac OS and ios

Core Spotlight

Core Spotlight

Core Spotlight

Core Spotlight

Core Spotlight

What is Core Spotlight Original search tool on ios base-friendly Spotlight API Search for content in apps Allows deep linking Ships on Mac OS and ios

What is Core Spotlight Original search tool on ios base-friendly Spotlight API Search for content in apps Allows deep linking Ships on Mac OS and ios Access CoreSpotlight search data from your app

What is Core Spotlight Original search tool on ios base-friendly Spotlight API Search for content in apps Allows deep linking Ships on Mac OS and ios Access CoreSpotlight search data from your app No zero-length files

Three Pieces Way to indicate property participation NSPropertyDescription.indexedBySpotlight Way to specify display name NSEntityDescription.coreSpotlightDisplayNameExpression Exporter

corespotlightdisplaynameexpression NSExpression Evaluated during Core Spotlight update object parameter will be an instance of NSManaged Can return anything Core Spotlight can accept CSLocalizedString

corespotlightdisplaynameexpression Keypath Property name Function lowercase:(displayname) FUNCTION:(castTo:(@ Class, @ MyUtilityClass ), @ displaynamefor:, self))

NSCoreCoreSpotlightDelegate Implements CSSearchableIndexDelegate Default implementations of all methods Uses a separate store on a background thread Initialize with NSPersistentStoreDescription + model Override point is NSCDCSD.attributeSet(for object:)

override func attributeset(for object: NSManaged) -> CSSearchableItemAttributeSet? { guard let attributeset = super.attributeset(for: object) else { return nil } if "Photo" == object.entity.name { let photo = object as! Photo let tags = photo.tags let localizedstring = localizedtagstring(photo) attributeset.setvalue(localizedstring, forcustomkey: attributekey!) } return attributeset; }

override func attributeset(for object: NSManaged) -> CSSearchableItemAttributeSet? { guard let attributeset = super.attributeset(for: object) else { return nil } if "Photo" == object.entity.name { let photo = object as! Photo let tags = photo.tags let localizedstring = localizedtagstring(photo) attributeset.setvalue(localizedstring, forcustomkey: attributekey!) } return attributeset; }

override func attributeset(for object: NSManaged) -> CSSearchableItemAttributeSet? { guard let attributeset = super.attributeset(for: object) else { return nil } if "Photo" == object.entity.name { let photo = object as! Photo let tags = photo.tags let localizedstring = localizedtagstring(photo) attributeset.setvalue(localizedstring, forcustomkey: attributekey!) } return attributeset; }

override func attributeset(for object: NSManaged) -> CSSearchableItemAttributeSet? { guard let attributeset = super.attributeset(for: object) else { return nil } if "Photo" == object.entity.name { let photo = object as! Photo let tags = photo.tags let localizedstring = localizedtagstring(photo) attributeset.setvalue(localizedstring, forcustomkey: attributekey!) } return attributeset; }

Demo

Non-Sharp Corners Will automatically export to Core Spotlight on first launch Uses Persistent History Tracking to ensure all data is pushed

Sharpish Corners Core Spotlight and Spotlight integration mutually exclusive entity.corespotlightdisplaynameexpression OR property.storedinexternalrecord Doesn t track results of batch operations

Sharpish Corners Entitlement to talk to Core Spotlight com.apple.application-identifier You need to handle the search result public func application(_ application: NSApplication, continue useractivity: NSUserActivity, restorationhandler: @escaping ([Any]) -> Void) -> Bool

public func application(_ application: NSApplication, continue useractivity: NSUserActivity, restorationhandler: @escaping ([Any]) -> Void) -> Bool { let userinfo = useractivity.userinfo as! NSDictionary let identifier = userinfo.value(forkey: kcssearchableitemactivityidentifier ) let uri = URL(string: identifier as! String) let coordinator = self.persistentcontainer.persistentstorecoordinator let managedid = managedid(forurirepresentation: uri!) } // insert your code here

public func application(_ application: NSApplication, continue useractivity: NSUserActivity, restorationhandler: @escaping ([Any]) -> Void) -> Bool { let userinfo = useractivity.userinfo as! NSDictionary let identifier = userinfo.value(forkey: kcssearchableitemactivityidentifier ) let uri = URL(string: identifier as! String) let coordinator = self.persistentcontainer.persistentstorecoordinator let managedid = managedid(forurirepresentation: uri!) } // insert your code here

public func application(_ application: NSApplication, continue useractivity: NSUserActivity, restorationhandler: @escaping ([Any]) -> Void) -> Bool { let userinfo = useractivity.userinfo as! NSDictionary let identifier = userinfo.value(forkey: kcssearchableitemactivityidentifier ) let uri = URL(string: identifier as! String) let coordinator = self.persistentcontainer.persistentstorecoordinator let managedid = managedid(forurirepresentation: uri!) } // insert your code here

public func application(_ application: NSApplication, continue useractivity: NSUserActivity, restorationhandler: @escaping ([Any]) -> Void) -> Bool { let userinfo = useractivity.userinfo as! NSDictionary let identifier = userinfo.value(forkey: kcssearchableitemactivityidentifier ) let uri = URL(string: identifier as! String) let coordinator = self.persistentcontainer.persistentstorecoordinator let managedid = managedid(forurirepresentation: uri!) } // insert your code here

public func application(_ application: NSApplication, continue useractivity: NSUserActivity, restorationhandler: @escaping ([Any]) -> Void) -> Bool { let userinfo = useractivity.userinfo as! NSDictionary let identifier = userinfo.value(forkey: kcssearchableitemactivityidentifier ) let uri = URL(string: identifier as! String) let coordinator = self.persistentcontainer.persistentstorecoordinator let managedid = managedid(forurirepresentation: uri!) } // insert your code here

Sharp Corners Up to you to delete old reference files x86_64 only

New Indexing API

Indexing Configure database for faster search One or more columns per index One or more indexes per column base will choose most efficient index based on query

Digression: Indexing Binary indexes Basic form Strict comparison only RTree indexes Optimized for ranged based searching

BTree 3 6 1 2 9 12 8

BTree Index 3 6 1 2 9 12 8

RTree R2 R5 R4 R1 R3 R6 R8 R10 R7 R9

RTree Index R1 R2 R6 R10 R4 R5 R3 R7 R8 R9

Current Indexing APIs Single property index NSAttributeDescription.isIndexed Multiple column index NSEntityDescription.compoundIndexes

Evolving Core Indexing Ability to support more index types More configurable indexing

More Powerful API NSFetchIndexDescription NSFetchIndexElementDescription NSEntityDescription.indexes Functions to control index use indexed:by:(indexname, propertyname) noindex:(propertyname)

NSFetchIndexElementDescription Property Type Binary RTree Direction

NSFetchIndexDescription Specify a single index Name Elements Predicate Validates index composition

Sharp Corners Can t mix and match element types Range indexes require numeric properties <= 32-bit Which can t be optional Create indexes last Changing entity hierarchy structurally drops indexes

Maybe Sharp Corners? Doesn t affect version hash Won t cause migration (with perf hit) Won t cause migration (user won t get updated indexes) Update model s versionhashmodifier to trigger migration SQL store will ignore unsupported indexes

Demo

Miscellaneous

New Attribute Types NSUUIDAttributeType NSUUID NSURIAttributeType NSURL

Persistent History Tracking History 201 Rishi Verma, Core Engineer

Story of the App

Story of the App Application View Context Background Context

Story of the App Application Shared Container Persistent Store View Context Background Context

Story of the App Application Shared Container Persistent Store View Context Background Context

Story of the App Application Shared Container Persistent Store View Context Background Context

Story of the App Application Shared Container Persistent Store View Context Remote Content Background Context

Story of the App Application Shared Container Persistent Store View Context Remote Content Background Context Document

Story of the App Application Shared Container Persistent Store View Context Remote Content Background Context Document Share

Story of the App Application Shared Container Persistent Store View Context Remote Content Background Context Document Share Photo Editing

Trains in the Night Application Shared Container Persistent Store View Context Remote Content Background Context Document Share Photo Editing

Trains in the Night Application Shared Container Persistent Store View Context Remote Content Background Context Document Share Photo Editing

Trains in the Night Application Shared Container Persistent Store View Context Remote Content Background Context Document Share Photo Editing

Trains in the Night Application Shared Container Persistent Store View Context Remote Content Background Context Document Share Photo Editing

Trains in the Night Shared Container Persistent Store Remote Content Document Share Photo Editing

Trains in the Night Application Shared Container Persistent Store View Context Remote Content Background Context Document Share Photo Editing

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

//Uncovering The Mystery - Made Easy, as simple as ABC let container = NSPersistentContainer(name: "WWDCDemo") let storedescription = container.persistentstoredescriptions.first storedescription?.setoption(true as NSNumber forkey:nspersistenthistorytrackingkey) container.loadpersistentstores { storedescription, error in }

//Uncovering The Mystery - Made Easy, as simple as ABC let container = NSPersistentContainer(name: "WWDCDemo") let storedescription = container.persistentstoredescriptions.first storedescription?.setoption(true as NSNumber forkey:nspersistenthistorytrackingkey) container.loadpersistentstores { storedescription, error in }

//Uncovering The Mystery - Made Easy, as simple as ABC let container = NSPersistentContainer(name: "WWDCDemo") let storedescription = container.persistentstoredescriptions.first storedescription?.setoption(true as NSNumber forkey:nspersistenthistorytrackingkey) container.loadpersistentstores { storedescription, error in }

//Uncovering The Mystery - Made Easy, as simple as ABC let container = NSPersistentContainer(name: "WWDCDemo") let storedescription = container.persistentstoredescriptions.first storedescription?.setoption(true as NSNumber forkey:nspersistenthistorytrackingkey) container.loadpersistentstores { storedescription, error in }

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos Application viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps 2 Document Files viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps 2 Document Files viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps 2 Document Files viewcontext backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps 2 Document Files viewcontext 3 Share Safari backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps 2 Document Files viewcontext 3 Share Safari backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps 2 Document Files viewcontext 3 Share Safari backgroundcontext

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext 2 Document Files 3 Share Safari backgroundcontext 4 Photos Photos

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext 2 Document Files 3 Share Safari backgroundcontext 4 Photos Photos

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext 2 Document Files 3 Share Safari backgroundcontext 4 Photos Photos

Ghost in the base Document Share Photos History Application 1 backgroundcontext Apps viewcontext 2 Document Files 3 Share Safari backgroundcontext 4 Photos Photos

//Reading History, the journey of a historian NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func fetchhistory(after date: Date) -> Self open class func fetchhistory(after token: NSPersistentHistoryToken?) -> Self open class func fetchhistory(after transaction: NSPersistentHistoryTransaction?) -> Self open var resulttype: NSPersistentHistoryResultType }

//Reading History, the journey of a historian NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func fetchhistory(after date: Date) -> Self open class func fetchhistory(after token: NSPersistentHistoryToken?) -> Self open class func fetchhistory(after transaction: NSPersistentHistoryTransaction?) -> Self open var resulttype: NSPersistentHistoryResultType }

//Reading History, the journey of a historian NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func fetchhistory(after date: Date) -> Self open class func fetchhistory(after token: NSPersistentHistoryToken?) -> Self open class func fetchhistory(after transaction: NSPersistentHistoryTransaction?) -> Self open var resulttype: NSPersistentHistoryResultType }

//Reading History, the journey of a historian NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func fetchhistory(after date: Date) -> Self open class func fetchhistory(after token: NSPersistentHistoryToken?) -> Self open class func fetchhistory(after transaction: NSPersistentHistoryTransaction?) -> Self open var resulttype: NSPersistentHistoryResultType }

//Reading History, the journey of a historian NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func fetchhistory(after date: Date) -> Self open class func fetchhistory(after token: NSPersistentHistoryToken?) -> Self open class func fetchhistory(after transaction: NSPersistentHistoryTransaction?) -> Self open var resulttype: NSPersistentHistoryResultType }

//Reading History, the journey of a historian NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func fetchhistory(after date: Date) -> Self open class func fetchhistory(after token: NSPersistentHistoryToken?) -> Self open class func fetchhistory(after transaction: NSPersistentHistoryTransaction?) -> Self open var resulttype: NSPersistentHistoryResultType }

//Reducing History, history is purged by the consumers NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func deletehistory(before date: Date) -> Self open class func deletehistory(before token: NSPersistentHistoryToken?) -> Self open class func deletehistory(before transaction: NSPersistentHistoryTransaction?) -> Self } //A single gatekeeper should be in charge of purging history

//Reducing History, history is purged by the consumers NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func deletehistory(before date: Date) -> Self open class func deletehistory(before token: NSPersistentHistoryToken?) -> Self open class func deletehistory(before transaction: NSPersistentHistoryTransaction?) -> Self } //A single gatekeeper should be in charge of purging history

//Reducing History, history is purged by the consumers NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func deletehistory(before date: Date) -> Self open class func deletehistory(before token: NSPersistentHistoryToken?) -> Self open class func deletehistory(before transaction: NSPersistentHistoryTransaction?) -> Self } //A single gatekeeper should be in charge of purging history

//Reducing History, history is purged by the consumers NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func deletehistory(before date: Date) -> Self open class func deletehistory(before token: NSPersistentHistoryToken?) -> Self open class func deletehistory(before transaction: NSPersistentHistoryTransaction?) -> Self } //A single gatekeeper should be in charge of purging history

//Reducing History, history is purged by the consumers NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func deletehistory(before date: Date) -> Self open class func deletehistory(before token: NSPersistentHistoryToken?) -> Self open class func deletehistory(before transaction: NSPersistentHistoryTransaction?) -> Self } //A single gatekeeper should be in charge of purging history

//Reducing History, history is purged by the consumers NEW open class NSPersistentHistoryChangeRequest : NSPersistentStoreRequest { open class func deletehistory(before date: Date) -> Self open class func deletehistory(before token: NSPersistentHistoryToken?) -> Self open class func deletehistory(before transaction: NSPersistentHistoryTransaction?) -> Self } //A single gatekeeper should be in charge of purging history

//NSPersistentHistoryTransaction NEW open class NSPersistentHistoryTransaction : NS, NSCopying { open var timestamp: Date { get } open var changes: [NSPersistentHistoryChange]? { get } open var transactionnumber: Int64 { get } open var storeid: String { get } open var bundleid: String { get } open var processid: String { get } open var contextname: String? { get } open var author: String? { get } open var token: NSPersistentHistoryToken { get } } // Get a notification that can be consumed by a NSManagedContext open func objectidnotification() -> Notification

//NSPersistentHistoryTransaction NEW open class NSPersistentHistoryTransaction : NS, NSCopying { open var timestamp: Date { get } open var changes: [NSPersistentHistoryChange]? { get } open var transactionnumber: Int64 { get } open var storeid: String { get } open var bundleid: String { get } open var processid: String { get } open var contextname: String? { get } open var author: String? { get } open var token: NSPersistentHistoryToken { get } } // Get a notification that can be consumed by a NSManagedContext open func objectidnotification() -> Notification

//NSPersistentHistoryTransaction NEW open class NSPersistentHistoryTransaction : NS, NSCopying { open var timestamp: Date { get } open var changes: [NSPersistentHistoryChange]? { get } open var transactionnumber: Int64 { get } open var storeid: String { get } open var bundleid: String { get } open var processid: String { get } open var contextname: String? { get } open var author: String? { get } open var token: NSPersistentHistoryToken { get } } // Get a notification that can be consumed by a NSManagedContext open func objectidnotification() -> Notification

//NSPersistentHistoryTransaction NEW open class NSPersistentHistoryTransaction : NS, NSCopying { open var timestamp: Date { get } open var changes: [NSPersistentHistoryChange]? { get } open var transactionnumber: Int64 { get } open var storeid: String { get } open var bundleid: String { get } open var processid: String { get } open var contextname: String? { get } open var author: String? { get } open var token: NSPersistentHistoryToken { get } } // Get a notification that can be consumed by a NSManagedContext open func objectidnotification() -> Notification

//NSManagedContext NEW /* Set the author for the context, this will be used as an identifier in the Persistent History Transactions (NSPersistentHistoryTransaction) */ open var transactionauthor: String?

//NSPersistentHistoryChange NEW public enum NSPersistentHistoryChangeType : Int { case insert case update case delete } open class NSPersistentHistoryChange : NS, NSCopying { open var changeid: Int64 { get } @NSCopying open var changedid: NSManagedID { get } open var changetype: NSPersistentHistoryChangeType { get } open var tombstone: [AnyHashable : Any]? { get } open var transaction: NSPersistentHistoryTransaction? { get } open var updatedproperties: Set<NSPropertyDescription>? { get } }

//NSPersistentHistoryChange NEW public enum NSPersistentHistoryChangeType : Int { case insert case update case delete } open class NSPersistentHistoryChange : NS, NSCopying { open var changeid: Int64 { get } @NSCopying open var changedid: NSManagedID { get } open var changetype: NSPersistentHistoryChangeType { get } open var tombstone: [AnyHashable : Any]? { get } open var transaction: NSPersistentHistoryTransaction? { get } open var updatedproperties: Set<NSPropertyDescription>? { get } }

//NSPersistentHistoryChange NEW public enum NSPersistentHistoryChangeType : Int { case insert case update case delete } open class NSPersistentHistoryChange : NS, NSCopying { open var changeid: Int64 { get } @NSCopying open var changedid: NSManagedID { get } open var changetype: NSPersistentHistoryChangeType { get } open var tombstone: [AnyHashable : Any]? { get } open var transaction: NSPersistentHistoryTransaction? { get } open var updatedproperties: Set<NSPropertyDescription>? { get } }

//NSPersistentHistoryChange NEW public enum NSPersistentHistoryChangeType : Int { case insert case update case delete } open class NSPersistentHistoryChange : NS, NSCopying { open var changeid: Int64 { get } @NSCopying open var changedid: NSManagedID { get } open var changetype: NSPersistentHistoryChangeType { get } open var tombstone: [AnyHashable : Any]? { get } open var transaction: NSPersistentHistoryTransaction? { get } open var updatedproperties: Set<NSPropertyDescription>? { get } }

Model Editor

Model Editor

Demo History In Action!

Recap History is fun!

Recap History is fun! Simple to enable Persistent History

Recap History is fun! Simple to enable Persistent History Uncover missing changes

Recap History is fun! Simple to enable Persistent History Uncover missing changes Never be in the dark again!

Migration Easy as pie

Migration Easy as pie We preserve as much history as possible

Migration Easy as pie We preserve as much history as possible Except when removing:

Migration Easy as pie We preserve as much history as possible Except when removing: Entities

Migration Easy as pie We preserve as much history as possible Except when removing: Entities Tombstones

Migration Easy as pie We preserve as much history as possible Except when removing: Entities Tombstones We will preserve the history until the last transaction that is complete

Performance Everything has consequences

Performance Everything has consequences Slight impact on save-and-batch operations

Performance Everything has consequences Slight impact on save-and-batch operations An increase in memory during such operations

Performance Everything has consequences Slight impact on save-and-batch operations An increase in memory during such operations Small storage overhead, but history can be purged

Summary

Summary CoreSpotlight easily share your app data with Spotlight

Summary CoreSpotlight easily share your app data with Spotlight New Indexing API faster searches, faster apps

Summary CoreSpotlight easily share your app data with Spotlight New Indexing API faster searches, faster apps Persistent History always know who dun it

https://bugreport.apple.com

More Information https://developer.apple.com/wwdc17/210

Related Sessions What s New in Cocoa Video Online What s New in Foundation Hall 2 Wednesday 11:00 AM Build Better Apps with CloudKit Dashboard Grand Ballroom B Thursday 10:00 AM What s New in Core Spotlight for ios and macos Grand Ballroom B Thursday 4:10 PM Cocoa Development Tips Grand Ballroom B Friday 9:00 AM

Labs Cocoa Lab Technology Lab C Wed 11:00AM-1:00PM Foundation Lab Technology Lab C Wed 1:00PM-3:30PM Core Lab Technology Lab C Wed 3:10PM-6:00PM CloudKit and icloud Lab Technology Lab C Thu 11:00AM-1:00PM Core Lab Technology Lab H Thu 4:10PM-6:00PM CoreSpotlight and Search Lab Technology Lab H Fri 9:00AM-11:00AM Cocoa Lab Technology Lab B Fri 1:50PM-3:20PM