UICollectionViewDataSourcePrefetching
* 이글은 Swift 3.0을 기준으로 작성되었습니다.
참고한 링크 목록:
https://littlebitesofcocoa.com/241-uicollectionview-cell-pre-fetching
https://littlebitesofcocoa.com/242-pre-loading-images-with-uicollectionviewdatasourceprefetching
https://www.captechconsulting.com/blogs/uicollectionview-prefetching-in-ios-10
Apple은 WWDC 2016 에서 iOS 10.0에 추가된 uicollectionview prefetching 기술에 대해 발표했다.
이 프리젠테이션에서 애플 개발자는 UICollectionView 의 Scrolling 시 프레임 드랍의 원인에 대해 "부드러운 스크롤을 유지하기 위해서 60 fps 이상으로 실행되어야 하며, 이는 특정 프레임을 16.65ms 안에 표시 해야 함을 의미한다. 이보다 표시하는 속도를 맞추지 못할 경우 프레임드랍이 발생한다"라고 설명했으며,
좋은 스크롤 퍼포먼스를 유지할 수 있는 방법중 하나로, iOS 10에 추가된 UICollectionView class 의 prefetching을 소개했다.
우선 iOS 10.0 이전의 UICollectionViewCell 의 lifecycle 을 살펴보자.
UICollectionViewCell LifeCycle (iOS 9.0 이하 버전)
1. (collectionView:cellforItemAtIndexpath:) datasource 메서드를 통해 reuse 셀이 생성된다.
이후 prepareForReuse을 호출해서 cell 재사용을 위한 준비작업을 수행하며 이 과정에서 cell의 contents 들을 셋팅하는 과정을 수행한다.
2. cell 이 scrollview 에 보여지기 직전, willDisplayCell:atIndexPath 메서드가 호출된다.
3. cell 이 scrollview 에서 벗어난뒤, didEndDisplayingCell:atIndexPath이 호출되며 cell은 re-use queue 에 반환된다.
* 스크롤 이동동작에 의해 cell 이 보여지고 사라질때 위의 동작들을 반복한다.
UICollectionViewCell LifeCycle (iOS 10)
iOS 10 에서는 iOS 9 의 3번과정까지 대부분 동일하다.
willDisplayCell 가 불릴때 실제로 view 에 표시되기 직전까지 호출되지 않도록 변경되었다.
또 didEndDisplayingCell:atIndexPath 메서드가 불리고 cell 은 즉시 re-use queue 에 반환되지 않고 약간동안 유지되도록 변경되었다.
이때문에 스크롤 방향이 다시 바뀌어 cell이 다시 표시되어야 할때, 이미 구성되었던 상태의 cell을 다시 보여주게 된다.
약간의 변경사항이지만 실제로 필요하기 전에 그리지 않으므로 일부 병목현상을 피할 수 있게 되었다.
prefetching 은 cell 이 표시되기전에 미리 datasource 를 준비할 수 있도록 하는 매커니즘 이다.
UICollectionViewDataSourcePrefetching 의 메서드는 다음과 같다.
func collectionView(UICollectionView, prefetchItemsAt: [IndexPath]) // required
func collectionView(UICollectionView, cancelPrefetchingForItemsAt: [IndexPath]) // optional
prefetchItemsAt 메서드는 collectionview 가 화면에 로드되고 셀을 로드할 준비가 끝나면 호출된다.
* cell을 준비하는 것이 아닌 cell을 구성할 datasource 를 준비 할 수 있도록 하는 함수이다.
prefetching 기술은 "adaptive technology"이고, 자동으로 호출 시점이 조정된다.
빠른 스크롤링은 실제로 prefetchItemsAt 메서드를 완전히 호출하지 않을 수 있다.
cancelPrefetchingForItemsAt 메서드는 준비된 datasource 를 정리 할수있는 옵션 메서드인데, 스크롤 방향을 반대로 적용할때 바로 cancel을 하게 되면 효과적으로 prefetching datasource를 활용하지 못할 수 있다.
collectionview 의 prefetcing 기술을 사용하지 않으려면 isPrefetchingEnabled 값을 false 로 적용하면 된다.
개인적인 의견:
Datasource 를 미리 준비하는 것이기 때문에 실제 display cell시에 부하가걸리는 동작 ( 고해상도 이미지를 imageview 에 set 하는데 한 화면에 여러 셀이 표시되는 경우 등 )은 display cell의 동작을 개선해야 한다.
따라서 모든 아이템에 대한 DataSource 를 미리 가지고 있는 경우에는 사용할 필요가 없으며, 데이터를 동적으로 로딩하는 경우에 또, 그 동작이 preload 를 통해 개선될 수 있는 경우에 사용하면 될것 같다.
추가 고려 사항:
isPrefetchingEnabled 이 활성화 되어있는 경우 ( iOS 10 에서는 default 로 활성화 인듯 하다 )
비동기 cell update 를 하고자 할때, cellforItem 을 통해 cell 을 얻어올때 nil 이 반환되는 경우가 발생한다.
비동기 cell update 를 사용할때에 cellforItem 을 사용한다면 다음 비활성화 코드를 넣어주자.
if #available(iOS 10.0, *) {
collectionView.isPrefetchingEnabled = false
} else {
// Fallback on earlier versions
}
관련 질문자 링크 첨부.
https://forums.developer.apple.com/thread/63064