View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Vidéos

Ouvrir le menu Fermer le menu
  • Collections
  • Toutes les vidéos
  • À propos

Plus de vidéos

  • À propos
  • Code
  • Build apps that share data through CloudKit and Core Data

    Learn how to easily build apps that share data between multiple iCloud users with NSPersistentCloudKitContainer. Discover how to create informative experiences around shared data and learn about the CloudKit technologies that support these features in Core Data.

    To get the most out of this session, check out our previous videos on NSPersistentCloudKitContainer: "Using Core Data With CloudKit" from WWDC19 and "Sync a Core Data store with the CloudKit public database" from WWDC20.

    Ressources

    • Synchronizing a local store to the cloud
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC22

    • Optimize your use of Core Data and CloudKit

    WWDC21

    • Bring Core Data concurrency to Swift and SwiftUI
    • There and back again: Data transfer on Apple Watch
    • What's new in CloudKit

    Tech Talks

    • Get the most out of CloudKit Sharing
  • Rechercher dans cette vidéo…
    • 5:20 - Add shared store description

      let privateStoreDescription = container.persistentStoreDescriptions.first!
      let storesURL = privateStoreDescription.url!.deletingLastPathComponent()
      privateStoreDescription.url = storesURL.appendingPathComponent("private.sqlite")
      privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
      privateStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
      
      let sharedStoreURL = storesURL.appendingPathComponent("shared.sqlite")
      let sharedStoreDescription = privateStoreDescription.copy()
      sharedStoreDescription.url = sharedStoreURL
      
      let containerIdentifier = privateStoreDescription.cloudKitContainerOptions!.containerIdentifier
      let sharedStoreOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
      sharedStoreOptions.databaseScope = .shared
      sharedStoreDescription.cloudKitContainerOptions = sharedStoreOptions
      container.persistentStoreDescriptions.append(sharedStoreDescription)
    • 6:00 - shareNoteAction, DetailViewController.swift

      @IBAction func shareNoteAction(_ sender: Any) {
        guard let barButtonItem = sender as? UIBarButtonItem else {
          fatalError("Not a UI Bar Button item??")
        }
      
        guard let post = self.post else {
          fatalError("Can't share without a post")
        }
      
        let container = AppDelegate.sharedAppDelegate.coreDataStack.persistentContainer
        let cloudSharingController = UICloudSharingController {
          (controller, completion: @escaping (CKShare?, CKContainer?, Error?) -> Void) in
          container.share([post], to: nil) { objectIDs, share, container, error in
      			if let actualShare = share {
      				post.managedObjectContext?.performAndWait {
      					actualShare[CKShare.SystemFieldKey.title] = post.title
      				}
      			}
      			completion(share, container, error)
      		}
        }
        cloudSharingController.delegate = self
      
        if let popover = cloudSharingController.popoverPresentationController {
          popover.barButtonItem = barButtonItem
        }
        present(cloudSharingController, animated: true) {}
      }
    • 17:06 - SharingProvider

      protocol SharingProvider {
        func isShared(object: NSManagedObject) -> Bool
        func isShared(objectID: NSManagedObjectID) -> Bool
        func participants(for object: NSManagedObject) -> [RenderableShareParticipant]
        func shares(matching objectIDs: [NSManagedObjectID]) throws -> [NSManagedObjectID: RenderableShare]
        func canEdit(object: NSManagedObject) -> Bool
        func canDelete(object: NSManagedObject) -> Bool
      }
    • 17:58 - Decorate table cells for shared posts, MainViewController.swift

      override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          guard let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as? PostCell else {
              fatalError("###\(#function): Failed to dequeue a PostCell. Check the cell reusable identifier in Main.storyboard.")
          }
          let post = dataProvider.fetchedResultsController.object(at: indexPath)
          cell.title.text = post.title
          cell.post = post
          cell.collectionView.reloadData()
          cell.collectionView.invalidateIntrinsicContentSize()
          
          if let attachments = post.attachments, attachments.allObjects.isEmpty {
              cell.hasAttachmentLabel.isHidden = true
          } else {
              cell.hasAttachmentLabel.isHidden = false
          }
          
          if sharingProvider.isShared(object: post) {
              let attachment = NSTextAttachment(image: UIImage(systemName: "person.circle")!)
              let attributedString = NSMutableAttributedString(attachment: attachment)
              attributedString.append(NSAttributedString(string: " " + (post.title ?? "")))
              cell.title.text = nil
              cell.title.attributedText = attributedString
          }
          return cell
      }
    • 18:44 - Testing the MainViewController's table view, TestMainViewController.swift

      func testSharedPostsGetDisclosure() {
          var sharedObjectIDs: Set<NSManagedObjectID> = Set()
          let context = coreDataStack.persistentContainer.viewContext
          self.generatePosts(in: context, postSaveBlock: { posts in
              for (index, post) in posts.enumerated() where (index % 4) == 0 {
                  sharedObjectIDs.insert(post.objectID)
              }
          })
          
          let provider = BlockBasedShareProvider(stack: coreDataStack)
          provider.isSharedBlock = sharedObjectIDs.contains
          mainViewController.sharingProvider = provider
          
          do {
              try mainViewController.dataProvider.fetchedResultsController.performFetch()
          } catch let error {
              XCTFail("Error while fetching \(error)")
          }
          
          reloadTableView()
          let rowCount = mainViewController.tableView(mainViewController.tableView,
                                                          numberOfRowsInSection: 0)
          XCTAssertEqual(100, rowCount)
          guard let expectedSharedImage = UIImage(systemName: "person.circle") else {
              XCTFail("Failed to get the person system image.")
              return
          }
          
          for index in 0..<rowCount {
              let indexPath = IndexPath(row: index, section: 0)
              let post = mainViewController.dataProvider.fetchedResultsController.object(at: indexPath)
              guard let title = post.title else {
                  XCTFail("All posts should have been given a title.")
                  return
              }
              
              guard let cell = mainViewController.tableView(mainViewController.tableView,
                                                                 cellForRowAt: indexPath) as? PostCell else {
                  XCTFail("Encountered an unexpected cell type in the main view controller's table view.")
                  return
              }
              
              if sharedObjectIDs.contains(post.objectID) {
                  guard let attributedText = cell.title.attributedText else {
                      XCTFail("Failed to get the attributed text of \(cell). Was it not set?")
                      return
                  }
                  
                  guard let attachment = attributedText.attributes(at: 0, effectiveRange: nil)[.attachment] as? NSTextAttachment else {
                      XCTFail("Expected an image attachment at the first character.")
                      return
                  }
                  
                  XCTAssertEqual(expectedSharedImage, attachment.image)
              } else {
                  XCTAssertEqual(cell.title.text, title)
              }
          }
      }
      
      class BlockBasedShareProvider: SharingProvider {
          var coreDataStack: CoreDataStack
          init(stack: CoreDataStack) {
              coreDataStack = stack
          }
          
          func isShared(object: NSManagedObject) -> Bool {
              return isShared(objectID: object.objectID)
          }
          
          public var isSharedBlock: ((_ object: NSManagedObjectID) -> Bool)? = nil
          func isShared(objectID: NSManagedObjectID) -> Bool {
              guard let block = isSharedBlock else {
                  return coreDataStack.isShared(objectID: objectID)
              }
              return block(objectID)
          }
          
          public var participantsBlock: ((_ object: NSManagedObject) -> [RenderableShareParticipant])? = nil
          func participants(for object: NSManagedObject) -> [RenderableShareParticipant] {
              guard let block = participantsBlock else {
                  return coreDataStack.participants(for: object)
              }
              return block(object)
          }
          
          public var sharesBlock: ((_ objectIDs: [NSManagedObjectID]) -> [NSManagedObjectID: RenderableShare])? = nil
          func shares(matching objectIDs: [NSManagedObjectID]) throws -> [NSManagedObjectID: RenderableShare] {
              guard let block = sharesBlock else {
                  return try coreDataStack.shares(matching: objectIDs)
              }
              return block(objectIDs)
          }
          
          public var canEditBlock: ((_ object: NSManagedObject) -> Bool)? = nil
          func canEdit(object: NSManagedObject) -> Bool {
              guard let block = canEditBlock else {
                  return coreDataStack.canEdit(object: object)
              }
              return block(object)
          }
          
          public var canDeleteBlock: ((_ object: NSManagedObject) -> Bool)? = nil
          func canDelete(object: NSManagedObject) -> Bool {
              guard let block = canDeleteBlock else {
                  return coreDataStack.canDelete(object: object)
              }
              return block(object)
          }
      }
    • 20:01 - CoreDataStack + Sharing, CoreDataStack.swift

      extension CoreDataStack: SharingProvider {
          func isShared(object: NSManagedObject) -> Bool {
              return isShared(objectID: object.objectID)
          }
      
          func isShared(objectID: NSManagedObjectID) -> Bool {
              var isShared = false
              if let persistentStore = objectID.persistentStore {
                  if persistentStore == sharedPersistentStore {
                      isShared = true
                  } else {
                      let container = persistentContainer
                      do {
                          let shares = try container.fetchShares(matching: [objectID])
                          if nil != shares.first {
                              isShared = true
                          }
                      } catch let error {
                          print("Failed to fetch share for \(objectID): \(error)")
                      }
                  }
              }
              return isShared
          }
          
          func participants(for object: NSManagedObject) -> [RenderableShareParticipant] {
              var participants = [CKShare.Participant]()
              do {
                  let container = persistentContainer
                  let shares = try container.fetchShares(matching: [object.objectID])
                  if let share = shares[object.objectID] {
                      participants = share.participants
                  }
              } catch let error {
                  print("Failed to fetch share for \(object): \(error)")
              }
              return participants
          }
          
          func shares(matching objectIDs: [NSManagedObjectID]) throws -> [NSManagedObjectID: RenderableShare] {
              return try persistentContainer.fetchShares(matching: objectIDs)
          }
          
          func canEdit(object: NSManagedObject) -> Bool {
              return persistentContainer.canUpdateRecord(forManagedObjectWith: object.objectID)
          }
              
          func canDelete(object: NSManagedObject) -> Bool {
              return persistentContainer.canDeleteRecord(forManagedObjectWith: object.objectID)
          }
      }

Developer Footer

  • Vidéos
  • WWDC21
  • Build apps that share data through CloudKit and Core Data
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines