-
Optimize your use of Core Data and CloudKit
Join us as we explore the three parts of the development cycle that can help you optimize your Core Data and CloudKit implementation. We'll show you how you can analyze your app's architecture and feature set to verify assumptions, explore changes in behavior after ingesting large data sets, and get actionable feedback to make improvements to your workflow.
To get the most out of this session, we recommend familiarity with syncing your data model to CloudKit.Ressources
Vidéos connexes
WWDC22
WWDC21
WWDC20
WWDC19
-
Rechercher dans cette vidéo…
-
-
4:35 - Define a large data generator
class LargeDataGenerator { func generateData(context: NSManagedObjectContext) throws { try context.performAndWait { for postCount in 1...60 { //add a post for attachmentCount in 1...11 { //add an attachment with an image let imageFileData = NSData(contentsOf: url!)! } } } } } -
5:07 - Testing a large data generator
class TestLargeDataGenerator: CoreDataCloudKitDemoUnitTestCase { func testGenerateData() throws { let context = self.coreDataStack.persistentContainer.newBackgroundContext() try self.generator.generateData(context: context) try context.performAndWait { let posts = try context.fetch(Post.fetchRequest()) for post in posts { self.verify(post: post, has: 11, matching: imageDatas) } } } } -
5:33 - Sync generated data in test
func testExportThenImport() throws { let exportContainer = newContainer(role: "export", postLoadEventType: .setup) try self.generator.generateData(context: exportContainer.newBackgroundContext()) self.expectation(for: .export, from: exportContainer) self.waitForExpectations(timeout: 1200) } -
6:35 - Expectation helper method
func expectation(for eventType: NSPersistentCloudKitContainer.EventType, from container: NSPersistentCloudKitContainer) -> [XCTestExpectation] { var expectations = [XCTestExpectation]() for store in container.persistentStoreCoordinator.persistentStores { let expectation = self.expectation( forNotification: NSPersistentCloudKitContainer.eventChangedNotification, object: container ) { notification in let userInfoKey = NSPersistentCloudKitContainer.eventNotificationUserInfoKey let event = notification.userInfo![userInfoKey] return (event.type == eventType) && (event.storeIdentifier == store.identifier) && (event.endDate != nil) } expectations.append(expectation) } return expectations } -
7:18 - Import data model in test
func testExportThenImport() throws { let exportContainer = newContainer(role: "export", postLoadEventType: .setup) try self.generator.generateData(context: exportContainer.newBackgroundContext()) self.expectation(for: .export, from: exportContainer) self.waitForExpectations(timeout: 1200) let importContainer = newContainer(role: "import", postLoadEventType: .import) self.waitForExpectations(timeout: 1200) } -
8:23 - Data generator alert action
UIAlertAction(title: "Generator: Large Data", style: .default) {_ in let generator = LargeDataGenerator() try generator.generateData(context: context) self.dismiss(animated: true) } -
10:50 - Eagerly generating thumbnail in data generator
func generateData(context: NSManagedObjectContext) throws { try context.performAndWait { for postCount in 1...60 { for attachmentCount in 1...11 { let attachment = Attachment(context: context) let imageData = ImageData(context: context) imageData.attachment = attachment imageData.data = autoreleasepool { let imageFileData = NSData(contentsOf: url!)! attachment.thumbnail = Attachment.thumbnail(from: imageFileData, thumbnailPixelSize: 80) return imageFileData } } } } } -
11:13 - Lazily generating thumbnail in data generator
func generateData(context: NSManagedObjectContext) throws { try context.performAndWait { for postCount in 1...60 { for attachmentCount in 1...11 { let attachment = Attachment(context: context) let imageData = ImageData(context: context) imageData.attachment = attachment imageData.data = autoreleasepool { return NSData(contentsOf: url!)! } } } } } -
14:14 - Problematic verifyPosts implementation
func verifyPosts(in context: NSManagedObjectContext) throws { try context.performAndWait { let fetchRequest = Post.fetchRequest() let posts = try context.fetch(fetchRequest) for post in posts { // verify post let attachments = post.attachments as! Set<Attachment> for attachment in attachments { XCTAssertNotNil(attachment.imageData) //verify image } } } } -
14:49 - Efficient verifyPosts implementation
func verifyPosts(in context: NSManagedObjectContext) throws { try context.performAndWait { let fetchRequest = Attachment.fetchRequest() fetchRequest.resultType = .managedObjectIDResultType let attachments = try context.fetch(fetchRequest) as! [NSManagedObjectID] for index in 0...attachments.count - 1 { let attachment = context.object(with: attachments[index]) as! Attachment //verify attachment let post = attachment.post! //verify post if 0 == (index % 10) { context.reset() } } } } -
20:41 - Display logs using `log stream`
# Application log stream --predicate 'process = "CoreDataCloudKitDemo" AND (sender = "CoreData" OR sender = "CloudKit")' # CloudKit log stream --predicate 'process = "cloudd" AND message contains[cd] "iCloud.com.example.CloudKitCoreDataDemo"' # Push log stream --predicate 'process = "apsd" AND message contains[cd] "CoreDataCloudKitDemo"' # Scheduling log stream --predicate 'process = "dasd" AND message contains[cd] "com.apple.coredata.cloudkit.activity" AND message contains[cd] "CEF8F02F-81DC-48E6-B293-6FCD357EF80F"' -
24:36 - Display logs with `log show`
log show --info --debug --predicate 'process = "apsd" AND message contains[cd] "iCloud.com.example.CloudKitCoreDataDemo"' system_logs.logarchive log show --info --debug --start "2022-06-04 09:40:00" --end "2022-06-04 09:42:00" --predicate 'process = "apsd" AND message contains[cd] "iCloud.com.example.CloudKitCoreDataDemo"' system_logs.logarchive -
25:17 - Provide a predicate to `log show`
log show --info --debug --start "2022-06-04 09:40:00" --end "2022-06-04 09:42:00" --predicate '(process = "CoreDataCloudKitDemo" AND (sender = "CoreData" or sender = "CloudKit")) OR (process = "cloudd" AND message contains[cd] "iCloud.com.example.CloudKitCoreDataDemo") OR (process = "apsd" AND message contains[cd] "CoreDataCloudKitDemo") OR (process = "dasd" AND message contains[cd] "com.apple.coredata.cloudkit.activity" AND message contains[cd] "CEF8F02F-81DC-48E6-B293-6FCD357EF80F")' system_logs.logarchive
-