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
  • Make blazing fast lists and collection views

    Build consistently smooth scrolling list and collection views: Explore the lifecycle of a cell and learn how to apply that knowledge to eliminate rough scrolling and missed frames. We'll also show you how to improve your overall scrolling experience and avoid costly hitches, with optimized image loading and automatic cell prefetching.

    To get the most out of this video, we recommend a basic familiarity with diffable data sources and compositional layout.

    Ressources

    • Building high-performance lists and collection views
    • UIKit
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC21

    • What's new in UIKit

    WWDC20

    • Advances in diffable data sources
    • Advances in UICollectionView

    Tech Talks

    • Explore UI animation hitches and the render loop
  • Rechercher dans cette vidéo…
    • 1:25 - Structuring data

      // Structuring data
      
      struct DestinationPost: Identifiable {
          // Each post has a unique identifier
          var id: String
          
          var title: String
          var numberOfLikes: Int
          var assetID: Asset.ID
      }
    • 2:01 - Setting up diffable data source

      // Setting up diffable data source
      
      class DestinationGridViewController: UIViewController {
          // Use DestinationPost.ID as the item identifier
          var dataSource: UICollectionViewDiffableDataSource<Section, DestinationPost.ID>
          
          private func setInitialData() {
              var snapshot = NSDiffableDataSourceSnapshot<Section, DestinationPost.ID>()
              
              // Only one section in this collection view, identified by Section.main
              snapshot.appendSections([.main])
              
              // Get identifiers of all destination posts in our model and add to initial snapshot
              let itemIdentifiers = postStore.allPosts.map { $0.id }
              snapshot.appendItems(itemIdentifiers)
              
              dataSource.apply(snapshot, animatingDifferences: false)
          }
      }
    • 3:47 - Creating cell registrations

      // Cell registrations
      
      let cellRegistration = UICollectionView.CellRegistration<DestinationPostCell,
                                                               DestinationPost.ID> {
          (cell, indexPath, postID) in
      
          let post = self.postsStore.fetchByID(postID)
          let asset = self.assetsStore.fetchByID(post.assetID)
          
          cell.titleView.text = post.region
          cell.imageView.image = asset.image
      }
    • 4:03 - Using cell registrations

      // Cell registrations
      
      let cellRegistration = UICollectionView.CellRegistration<DestinationPostCell,
                                                               DestinationPost.ID> {
          (cell, indexPath, postID) in
          ...
      }
         
      let dataSource = UICollectionViewDiffableDataSource<Section.ID,
                                                          DestinationPost.ID>(collectionView: cv){
          (collectionView, indexPath, postID) in
        
           return collectionView.dequeueConfiguredReusableCell(using: cellRegistration,
                                                                 for: indexPath,
                                                                item: postID)
      }
    • 13:58 - Existing cell registration

      // Existing cell registration
      
      let cellRegistration = UICollectionView.CellRegistration<DestinationPostCell,
                                                               DestinationPost.ID> {
          (cell, indexPath, postID) in
      
          let post = self.postsStore.fetchByID(postID)
          let asset = self.assetsStore.fetchByID(post.assetID)
          
          cell.titleView.text = post.region
          cell.imageView.image = asset.image
      }
    • 14:17 - Updating cells asynchronously (wrong)

      // Updating cells asynchronously 
      
      let cellRegistration = UICollectionView.CellRegistration<DestinationPostCell,
                                                               DestinationPost.ID> {
          (cell, indexPath, postID) in
      
          let post = self.postsStore.fetchByID(postID)
          let asset = self.assetsStore.fetchByID(post.assetID)
          
          if asset.isPlaceholder {
              self.assetsStore.downloadAsset(post.assetID) { asset in
                  cell.imageView.image = asset.image
              }
          }
          
          cell.titleView.text = post.region
          cell.imageView.image = asset.image
      }
    • 15:15 - Reconfiguring items

      private func setPostNeedsUpdate(id: DestinationPost.ID) {
          var snapshot = dataSource.snapshot()
          snapshot.reconfigureItems([id])
          dataSource.apply(snapshot, animatingDifferences: true)
      }
    • 15:23 - Updating cells asynchronously (correct)

      // Updating cells asynchronously
      
      let cellRegistration = UICollectionView.CellRegistration<DestinationPostCell,
                                                               DestinationPost.ID> {
          (cell, indexPath, postID) in
      
          let post = self.postsStore.fetchByID(postID)
          let asset = self.assetsStore.fetchByID(post.assetID)
          
          if asset.isPlaceholder {
              self.assetsStore.downloadAsset(post.assetID) { _ in
                  self.setPostNeedsUpdate(id: post.id)
              }
          }
          
          cell.titleView.text = post.region
          cell.imageView.image = asset.image
      }
    • 15:52 - Data source prefetching

      // Data source prefetching
      
      var prefetchingIndexPaths: [IndexPath: Cancellable]
      
      func collectionView(_ collectionView: UICollectionView,
                          prefetchItemsAt indexPaths [IndexPath]) {
         // Begin download work
          for indexPath in indexPaths {
              guard let post = fetchPost(at: indexPath) else { continue }
              prefetchingIndexPaths[indexPath] = assetsStore.loadAssetByID(post.assetID)
          }
      }
      
      func collectionView(_ collectionView: UICollectionView,
                          cancelPrefetchingForItemsAt indexPaths: [IndexPath]) {
          // Stop fetching
          for indexPath in indexPaths {
              prefetchingIndexPaths[indexPath]?.cancel()
          }
      }
    • 18:43 - Using prepareForDisplay

      // Using prepareForDisplay
      
      // Initialize the full image
      let fullImage = UIImage()
      
      // Set a placeholder before preparation
      imageView.image = placeholderImage
      
      // Prepare the full image
      fullImage.prepareForDisplay { preparedImage in
          DispatchQueue.main.async {
             self.imageView.image = preparedImage
          }
      }
    • 19:51 - Asset downloading without image preparation

      // Asset downloading – before image preparation
      
      func downloadAsset(_ id: Asset.ID,
                         completionHandler: @escaping (Asset) -> Void) -> Cancellable {
        
          return fetchAssetFromServer(assetID: id) { asset in
              DispatchQueue.main.async {
                  completionHandler(asset)
              }
          }
      }
    • 19:58 - Asset downloading with image preparation

      // Asset downloading – with image preparation
      
      func downloadAsset(_ id: Asset.ID,
                         completionHandler: @escaping (Asset) -> Void) -> Cancellable {
          // Check for an already prepared image
          if let preparedAsset = imageCache.fetchByID(id) {
              completionHandler(preparedAsset)
              return AnyCancellable {}
          }
          return fetchAssetFromServer(assetID: id) { asset in
              asset.image.prepareForDisplay { preparedImage in
                  // Store the image in the cache.
                  self.imageCache.add(asset: asset.withImage(preparedImage!))
                  DispatchQueue.main.async {
                      completionHandler(asset)
                  }
              }
          }
      }
    • 20:50 - Using prepareThumbnail

      // Using prepareThumbnail
      
      // Initialize the full image
      let profileImage = UIImage(...)
      
      // Set a placeholder before preparation
      posterAvatarView.image = placeholderImage
      
      // Prepare the image
      profileImage.prepareThumbnail(of: posterAvatarView.bounds.size) { thumbnailImage in
          DispatchQueue.main.async {
              self.posterAvatarView.image = thumbnailImage
          }
      }

Developer Footer

  • Vidéos
  • WWDC21
  • Make blazing fast lists and collection views
  • 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