SlideShare ist ein Scribd-Unternehmen logo
1 von 34
Downloaden Sie, um offline zu lesen
Andrea Prearo
Master Software Engineer - iOS @ Capital One SF
https://github.com/andrea-prearo
https://medium.com/@andrea.prearo
https://twitter.com/andrea_prearo
Optimize Collection View
Scrolling
Scrolling and User Experience
UICollectionView is designed to support displaying sets of data
that can be scrolled. However, when displaying a very large
amount of data, it could be very tricky to achieve a perfectly
smooth scrolling. This is not ideal because it negatively affects the
user experience.
Strategies to achieve Smooth
Scrolling
Example: Display a set of users
Cells Rendering is a Critical Task
Cell Lifecycle (iOS9+)
1. Request the cell: collectionView(_:cellForItemAt:)
2. Display the cell: collectionView(_:willDisplay:forItemAt:)
3. Remove the cell: collectionView(_:didEndDisplaying:forItemAt:)
Basic cell rendering
override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Collection view cells are reused and should be dequeued using a cell identifier.
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "reuseIdentifier", for: indexPath)
// Configure the cell ...
return cell
}
User Model
enum Role: String, Codable {
case unknown = "Unknown"
case user = "User"
case owner = "Owner"
case admin = "Admin"
static func get(from: String) -> Role {
if from == user.rawValue {
return .user
} else if from == owner.rawValue {
return .owner
} else if from == admin.rawValue {
return .admin
}
return .unknown
}
}
struct User: Codable {
enum CodingKeys: String, CodingKey {
case avatarUrl = "avatar"
case username
case role
}
let avatarUrl: String
let username: String
let role: Role
init(avatarUrl: String, username: String, role: Role) {
self.avatarUrl = avatarUrl
self.username = username
self.role = role
}
}
User View Model (MVVM)
struct UserViewModel {
let avatarUrl: String
let username: String
let role: Role
let roleText: String
init(user: User) {
// Avatar
avatarUrl = user.avatarUrl
// Username
username = user.username
// Role
role = user.role
roleText = user.role.rawValue
}
}
Fetch Data Asynchronously and Cache
View Models
• Avoid blocking the main thread while fetching data
• Update the collection view right after we retrieve the data
User View Model Controller
Wrap and Cache View Model
class UserViewModelController {
private var viewModels: [UserViewModel?] = []
[...]
var viewModelsCount: Int {
return viewModels.count
}
func viewModel(at index: Int) -> UserViewModel? {
guard index >= 0 && index < viewModelsCount else { return nil }
return viewModels[index]
}
}
User View Model Controller
Asynchronous Data Fetch
func retrieveUsers(_ completionBlock: @escaping (_ success: Bool, _ error: NSError?) -> ()) {
let urlString = ... // Users Web Service URL
let session = URLSession.shared
guard let url = URL(string: urlString) else {
completionBlock(false, nil)
return
}
let task = session.dataTask(with: url) { [weak self] (data, response, error) in
guard let strongSelf = self else { return }
guard let jsonData = data, error == nil else {
completionBlock(false, error as NSError?)
return
}
if let users = UserViewModelController.parse(jsonData) {
strongSelf.viewModels = UserViewModelController.initViewModels(users)
completionBlock(true, nil)
} else {
completionBlock(false, NSError.createError(0, description: "JSON parsing error"))
}
}
task.resume()
}
User View Model Controller Extension
Parse JSON
private extension UserViewModelController {
static func parse(_ jsonData: Data) -> [User?]? {
do {
return try JSONDecoder().decode([User].self, from: jsonData)
} catch {
return nil
}
}
static func initViewModels(_ users: [User?]) -> [UserViewModel?] {
return users.map { user in
if let user = user {
return UserViewModel(user: user)
} else {
return nil
}
}
}
}
Scenarios for Fetching Data
• Only the when loading the collection view the first time, by
placing it in viewDidLoad()
• Every time the collection view is displayed, by placing it in
viewWillAppear(_:)
• On user demand (for instance via a pull-down-to-refresh), by
placing it in the method call that will take care of refreshing
the data
Load Images Asynchronously and Cache
Them
Extend UIImage and Leverage URLSession
extension UIImage {
static func downloadImageFromUrl(_ url: String, completionHandler: @escaping (UIImage?) -> Void) {
guard let url = URL(string: url) else {
completionHandler(nil)
return
}
let task: URLSessionDataTask = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in
guard let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data) else {
completionHandler(nil)
return
}
completionHandler(image)
})
task.resume()
}
}
Open Source Libraries for Asynchronous
Image Downloading and Caching
• SDWebImage
• AlamofireImage
Customize the Cell
Subclass the Default Cell
class UserCell: UICollectionViewCell {
@IBOutlet weak var avatar: UIImageView!
@IBOutlet weak var username: UILabel!
@IBOutlet weak var role: UILabel!
func configure(_ viewModel: UserViewModel) {
UIImage.downloadImageFromUrl(viewModel.avatarUrl) { [weak self] (image) in
guard let strongSelf = self,
let image = image else {
return
}
strongSelf.avatar.image = image
}
username.text = viewModel.username
role.text = viewModel.roleText
}
}
Use Opaque Layers and Avoid Gradients
class UserCell: UICollectionViewCell {
@IBOutlet weak var avatar: UIImageView!
@IBOutlet weak var username: UILabel!
@IBOutlet weak var role: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
setOpaqueBackground()
[...]
}
}
private extension UserCell {
static let DefaultBackgroundColor = UIColor.groupTableViewBackgroundColor
func setOpaqueBackground() {
alpha = 1.0
backgroundColor = UserCell.DefaultBackgroundColor
avatar.alpha = 1.0
avatar.backgroundColor = UserCell.DefaultBackgroundColor
}
}
Putting Everything Together
Optimized Cell Rendering
override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserCell", for: indexPath) as! UserCell
if let viewModel = userViewModelController.viewModel(at: indexPath.row) {
cell.configure(viewModel)
}
return cell
}
Cell Rendering should now be really fast
• We are using the cached View Model data
• We are fetching the images asynchronously
Calculate your Cell Size
Implement collectionView(_:layout:sizeForItemAt:)
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
// Calculate the appropriate cell size
return CGSize(width: ..., height: ...)
}
Handle Size Classes and Orientation
Changes
Implement viewWillTransition(to:with:)
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
collectionView?.collectionViewLayout.invalidateLayout()
}
Refresh Collection View Layout when
• Transitioning to a different Size Class
• Rotating the device
Dynamically Adjust Cell Layout
Override apply(_:)
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
// Customize the cell layout
[...]
}
Example: Adjust multi-line UILabel
Maximum Width using
preferredMaxLayoutWidth
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
// Customize the cell layout
let width = CGRectGetWidth(layoutAttributes.frame)
username.preferredMaxLayoutWidth = width - 16
}
Boost Smooth Scrolling with iOS
10 Pre-Fetching APIs
Choppy Scrolling
Dropped Frame I
Choppy Scrolling
Dropped Frame II
Dropped Frames
The most common source of dropped frames is loading
expensive data models for a cell from the main thread
Common scenarios:
• Loading images from an URL
• Accessing items from a database or CoreData
Updates to Cell Lifecycle in iOS10
1. The OS calls collectionView(_:cellForItemAt:) much earlier than it used to:
• Cell loading is performed way before the cell needs to be displayed
• The cell may not end up being displayed at all
2. Cell goes off the visible field:
• collectionView(_:didEndDisplaying:forItemAt:) doesn't force immediate recycle for the cell
• collectionView(_:willDisplay:forItemAt:) may not require to reload cell content
Multi-column Layouts Cell Lifecycle
iOS9
Multi-column Layouts Cell Lifecycle
iOS10
Pre-Fetching API
• Introduced with iOS10
• Adaptive Technology
• Enabled by default
Best Practices
• Set up cell content in collectionView(_:cellForItemAt:)
• Don't use collectionView(_:willDisplay:forItemAt:) and
collectionView(_:didEndDisplaying:forItemAt:)
• Cell may not be displayed even if collectionView(_:cellForItemAt:) gets called (Plan for this!)
Pre-Fetching
• collectionView(_:prefetchItemsAt:) (required) — Initiate the
asynchronous loading of cell content (GCD or
OperationQueue)
• collectionView(_:cancelPrefetchingForItemsAt:)
(optional) — Cancel pending cell content loading
Code samples
All code is available on GitHub:
SmoothScrolling - Collection View
... Swift 4 Code Update In Progress ...

Weitere ähnliche Inhalte

Was ist angesagt?

ADF - Layout Managers and Skinning
ADF - Layout Managers and SkinningADF - Layout Managers and Skinning
ADF - Layout Managers and SkinningGeorge Estebe
 
Django class based views for beginners
Django class based views for beginnersDjango class based views for beginners
Django class based views for beginnersSpin Lai
 
Learning jQuery in 30 minutes
Learning jQuery in 30 minutesLearning jQuery in 30 minutes
Learning jQuery in 30 minutesSimon Willison
 
Java script Basic
Java script BasicJava script Basic
Java script BasicJaya Kumari
 
Spring cheat sheet
Spring cheat sheetSpring cheat sheet
Spring cheat sheetMark Papis
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOPDzmitry Naskou
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldJorge Vásquez
 
State of the art authentication mit Java EE 8
State of the art authentication mit Java EE 8State of the art authentication mit Java EE 8
State of the art authentication mit Java EE 8OPEN KNOWLEDGE GmbH
 
Asp.net state management
Asp.net state managementAsp.net state management
Asp.net state managementpriya Nithya
 
Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaVladimir Kostyukov
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Hitesh-Java
 
CSS3 2D/3D transform
CSS3 2D/3D transformCSS3 2D/3D transform
CSS3 2D/3D transformKenny Lee
 
Bootstrap PPT by Mukesh
Bootstrap PPT by MukeshBootstrap PPT by Mukesh
Bootstrap PPT by MukeshMukesh Kumar
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module PatternsNicholas Jansma
 

Was ist angesagt? (20)

ADF - Layout Managers and Skinning
ADF - Layout Managers and SkinningADF - Layout Managers and Skinning
ADF - Layout Managers and Skinning
 
Django class based views for beginners
Django class based views for beginnersDjango class based views for beginners
Django class based views for beginners
 
Learning jQuery in 30 minutes
Learning jQuery in 30 minutesLearning jQuery in 30 minutes
Learning jQuery in 30 minutes
 
Recycler view
Recycler viewRecycler view
Recycler view
 
Oracle Database View
Oracle Database ViewOracle Database View
Oracle Database View
 
Java script Basic
Java script BasicJava script Basic
Java script Basic
 
Spring cheat sheet
Spring cheat sheetSpring cheat sheet
Spring cheat sheet
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorld
 
State of the art authentication mit Java EE 8
State of the art authentication mit Java EE 8State of the art authentication mit Java EE 8
State of the art authentication mit Java EE 8
 
Asp.net state management
Asp.net state managementAsp.net state management
Asp.net state management
 
Defensive Apex Programming
Defensive Apex ProgrammingDefensive Apex Programming
Defensive Apex Programming
 
Purely Functional Data Structures in Scala
Purely Functional Data Structures in ScalaPurely Functional Data Structures in Scala
Purely Functional Data Structures in Scala
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans
 
Spring boot
Spring bootSpring boot
Spring boot
 
CSS3 2D/3D transform
CSS3 2D/3D transformCSS3 2D/3D transform
CSS3 2D/3D transform
 
Angular Data Binding
Angular Data BindingAngular Data Binding
Angular Data Binding
 
Bootstrap PPT by Mukesh
Bootstrap PPT by MukeshBootstrap PPT by Mukesh
Bootstrap PPT by Mukesh
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Javascript Module Patterns
Javascript Module PatternsJavascript Module Patterns
Javascript Module Patterns
 

Ähnlich wie Optimize CollectionView Scrolling

Smooth scrolling in UITableView and UICollectionView
Smooth scrolling in UITableView and UICollectionViewSmooth scrolling in UITableView and UICollectionView
Smooth scrolling in UITableView and UICollectionViewAndrea Prearo
 
Using a model view-view model architecture for iOS apps
Using a model view-view model architecture for iOS appsUsing a model view-view model architecture for iOS apps
Using a model view-view model architecture for iOS appsallanh0526
 
Swift Tableview iOS App Development
Swift Tableview iOS App DevelopmentSwift Tableview iOS App Development
Swift Tableview iOS App DevelopmentKetan Raval
 
Introduction to Backbone.js for Rails developers
Introduction to Backbone.js for Rails developersIntroduction to Backbone.js for Rails developers
Introduction to Backbone.js for Rails developersAoteaStudios
 
Creating Single Page Web App using Backbone JS
Creating Single Page Web App using Backbone JSCreating Single Page Web App using Backbone JS
Creating Single Page Web App using Backbone JSAkshay Mathur
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsHassan Abid
 
How to instantiate any view controller for free
How to instantiate any view controller for freeHow to instantiate any view controller for free
How to instantiate any view controller for freeBenotCaron
 
Ui perfomance
Ui perfomanceUi perfomance
Ui perfomanceCleveroad
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'sAntônio Roberto Silva
 
Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8Ovadiah Myrgorod
 
Android App Development - 04 Views and layouts
Android App Development - 04 Views and layoutsAndroid App Development - 04 Views and layouts
Android App Development - 04 Views and layoutsDiego Grancini
 
Writing HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAEWriting HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAERon Reiter
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedToru Wonyoung Choi
 
Daniel Jalkut - dotSwift 2019
Daniel Jalkut - dotSwift 2019Daniel Jalkut - dotSwift 2019
Daniel Jalkut - dotSwift 2019DanielJalkut
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30fiyuer
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developersPavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 

Ähnlich wie Optimize CollectionView Scrolling (20)

Smooth scrolling in UITableView and UICollectionView
Smooth scrolling in UITableView and UICollectionViewSmooth scrolling in UITableView and UICollectionView
Smooth scrolling in UITableView and UICollectionView
 
Using a model view-view model architecture for iOS apps
Using a model view-view model architecture for iOS appsUsing a model view-view model architecture for iOS apps
Using a model view-view model architecture for iOS apps
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Eclipse Tricks
Eclipse TricksEclipse Tricks
Eclipse Tricks
 
Swift Tableview iOS App Development
Swift Tableview iOS App DevelopmentSwift Tableview iOS App Development
Swift Tableview iOS App Development
 
Introduction to Backbone.js for Rails developers
Introduction to Backbone.js for Rails developersIntroduction to Backbone.js for Rails developers
Introduction to Backbone.js for Rails developers
 
Creating Single Page Web App using Backbone JS
Creating Single Page Web App using Backbone JSCreating Single Page Web App using Backbone JS
Creating Single Page Web App using Backbone JS
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
How to instantiate any view controller for free
How to instantiate any view controller for freeHow to instantiate any view controller for free
How to instantiate any view controller for free
 
Ui perfomance
Ui perfomanceUi perfomance
Ui perfomance
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8
 
Android App Development - 04 Views and layouts
Android App Development - 04 Views and layoutsAndroid App Development - 04 Views and layouts
Android App Development - 04 Views and layouts
 
Writing HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAEWriting HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAE
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO Extended
 
Daniel Jalkut - dotSwift 2019
Daniel Jalkut - dotSwift 2019Daniel Jalkut - dotSwift 2019
Daniel Jalkut - dotSwift 2019
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 

Kürzlich hochgeladen

W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 

Kürzlich hochgeladen (20)

W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 

Optimize CollectionView Scrolling

  • 1. Andrea Prearo Master Software Engineer - iOS @ Capital One SF https://github.com/andrea-prearo https://medium.com/@andrea.prearo https://twitter.com/andrea_prearo
  • 3. Scrolling and User Experience UICollectionView is designed to support displaying sets of data that can be scrolled. However, when displaying a very large amount of data, it could be very tricky to achieve a perfectly smooth scrolling. This is not ideal because it negatively affects the user experience.
  • 4. Strategies to achieve Smooth Scrolling Example: Display a set of users
  • 5. Cells Rendering is a Critical Task Cell Lifecycle (iOS9+) 1. Request the cell: collectionView(_:cellForItemAt:) 2. Display the cell: collectionView(_:willDisplay:forItemAt:) 3. Remove the cell: collectionView(_:didEndDisplaying:forItemAt:)
  • 6. Basic cell rendering override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // Collection view cells are reused and should be dequeued using a cell identifier. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "reuseIdentifier", for: indexPath) // Configure the cell ... return cell }
  • 7. User Model enum Role: String, Codable { case unknown = "Unknown" case user = "User" case owner = "Owner" case admin = "Admin" static func get(from: String) -> Role { if from == user.rawValue { return .user } else if from == owner.rawValue { return .owner } else if from == admin.rawValue { return .admin } return .unknown } } struct User: Codable { enum CodingKeys: String, CodingKey { case avatarUrl = "avatar" case username case role } let avatarUrl: String let username: String let role: Role init(avatarUrl: String, username: String, role: Role) { self.avatarUrl = avatarUrl self.username = username self.role = role } }
  • 8. User View Model (MVVM) struct UserViewModel { let avatarUrl: String let username: String let role: Role let roleText: String init(user: User) { // Avatar avatarUrl = user.avatarUrl // Username username = user.username // Role role = user.role roleText = user.role.rawValue } }
  • 9. Fetch Data Asynchronously and Cache View Models • Avoid blocking the main thread while fetching data • Update the collection view right after we retrieve the data
  • 10. User View Model Controller Wrap and Cache View Model class UserViewModelController { private var viewModels: [UserViewModel?] = [] [...] var viewModelsCount: Int { return viewModels.count } func viewModel(at index: Int) -> UserViewModel? { guard index >= 0 && index < viewModelsCount else { return nil } return viewModels[index] } }
  • 11. User View Model Controller Asynchronous Data Fetch func retrieveUsers(_ completionBlock: @escaping (_ success: Bool, _ error: NSError?) -> ()) { let urlString = ... // Users Web Service URL let session = URLSession.shared guard let url = URL(string: urlString) else { completionBlock(false, nil) return } let task = session.dataTask(with: url) { [weak self] (data, response, error) in guard let strongSelf = self else { return } guard let jsonData = data, error == nil else { completionBlock(false, error as NSError?) return } if let users = UserViewModelController.parse(jsonData) { strongSelf.viewModels = UserViewModelController.initViewModels(users) completionBlock(true, nil) } else { completionBlock(false, NSError.createError(0, description: "JSON parsing error")) } } task.resume() }
  • 12. User View Model Controller Extension Parse JSON private extension UserViewModelController { static func parse(_ jsonData: Data) -> [User?]? { do { return try JSONDecoder().decode([User].self, from: jsonData) } catch { return nil } } static func initViewModels(_ users: [User?]) -> [UserViewModel?] { return users.map { user in if let user = user { return UserViewModel(user: user) } else { return nil } } } }
  • 13. Scenarios for Fetching Data • Only the when loading the collection view the first time, by placing it in viewDidLoad() • Every time the collection view is displayed, by placing it in viewWillAppear(_:) • On user demand (for instance via a pull-down-to-refresh), by placing it in the method call that will take care of refreshing the data
  • 14. Load Images Asynchronously and Cache Them Extend UIImage and Leverage URLSession extension UIImage { static func downloadImageFromUrl(_ url: String, completionHandler: @escaping (UIImage?) -> Void) { guard let url = URL(string: url) else { completionHandler(nil) return } let task: URLSessionDataTask = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in guard let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200, let mimeType = response?.mimeType, mimeType.hasPrefix("image"), let data = data, error == nil, let image = UIImage(data: data) else { completionHandler(nil) return } completionHandler(image) }) task.resume() } }
  • 15. Open Source Libraries for Asynchronous Image Downloading and Caching • SDWebImage • AlamofireImage
  • 16. Customize the Cell Subclass the Default Cell class UserCell: UICollectionViewCell { @IBOutlet weak var avatar: UIImageView! @IBOutlet weak var username: UILabel! @IBOutlet weak var role: UILabel! func configure(_ viewModel: UserViewModel) { UIImage.downloadImageFromUrl(viewModel.avatarUrl) { [weak self] (image) in guard let strongSelf = self, let image = image else { return } strongSelf.avatar.image = image } username.text = viewModel.username role.text = viewModel.roleText } }
  • 17. Use Opaque Layers and Avoid Gradients class UserCell: UICollectionViewCell { @IBOutlet weak var avatar: UIImageView! @IBOutlet weak var username: UILabel! @IBOutlet weak var role: UILabel! override func awakeFromNib() { super.awakeFromNib() setOpaqueBackground() [...] } } private extension UserCell { static let DefaultBackgroundColor = UIColor.groupTableViewBackgroundColor func setOpaqueBackground() { alpha = 1.0 backgroundColor = UserCell.DefaultBackgroundColor avatar.alpha = 1.0 avatar.backgroundColor = UserCell.DefaultBackgroundColor } }
  • 18. Putting Everything Together Optimized Cell Rendering override open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserCell", for: indexPath) as! UserCell if let viewModel = userViewModelController.viewModel(at: indexPath.row) { cell.configure(viewModel) } return cell }
  • 19. Cell Rendering should now be really fast • We are using the cached View Model data • We are fetching the images asynchronously
  • 20. Calculate your Cell Size Implement collectionView(_:layout:sizeForItemAt:) func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize // Calculate the appropriate cell size return CGSize(width: ..., height: ...) }
  • 21. Handle Size Classes and Orientation Changes Implement viewWillTransition(to:with:) override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) collectionView?.collectionViewLayout.invalidateLayout() }
  • 22. Refresh Collection View Layout when • Transitioning to a different Size Class • Rotating the device
  • 23. Dynamically Adjust Cell Layout Override apply(_:) override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { super.apply(layoutAttributes) // Customize the cell layout [...] }
  • 24. Example: Adjust multi-line UILabel Maximum Width using preferredMaxLayoutWidth override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { super.apply(layoutAttributes) // Customize the cell layout let width = CGRectGetWidth(layoutAttributes.frame) username.preferredMaxLayoutWidth = width - 16 }
  • 25. Boost Smooth Scrolling with iOS 10 Pre-Fetching APIs
  • 28. Dropped Frames The most common source of dropped frames is loading expensive data models for a cell from the main thread Common scenarios: • Loading images from an URL • Accessing items from a database or CoreData
  • 29. Updates to Cell Lifecycle in iOS10 1. The OS calls collectionView(_:cellForItemAt:) much earlier than it used to: • Cell loading is performed way before the cell needs to be displayed • The cell may not end up being displayed at all 2. Cell goes off the visible field: • collectionView(_:didEndDisplaying:forItemAt:) doesn't force immediate recycle for the cell • collectionView(_:willDisplay:forItemAt:) may not require to reload cell content
  • 30. Multi-column Layouts Cell Lifecycle iOS9
  • 31. Multi-column Layouts Cell Lifecycle iOS10
  • 32. Pre-Fetching API • Introduced with iOS10 • Adaptive Technology • Enabled by default Best Practices • Set up cell content in collectionView(_:cellForItemAt:) • Don't use collectionView(_:willDisplay:forItemAt:) and collectionView(_:didEndDisplaying:forItemAt:) • Cell may not be displayed even if collectionView(_:cellForItemAt:) gets called (Plan for this!)
  • 33. Pre-Fetching • collectionView(_:prefetchItemsAt:) (required) — Initiate the asynchronous loading of cell content (GCD or OperationQueue) • collectionView(_:cancelPrefetchingForItemsAt:) (optional) — Cancel pending cell content loading
  • 34. Code samples All code is available on GitHub: SmoothScrolling - Collection View ... Swift 4 Code Update In Progress ...