-
[iOS] Cell LifeCycle (UITableView, UICollectionView)iOS/iOS 2020. 8. 28. 02:28
안녕하세요 :)
오늘은 Cell의 LifeCycle에 대해 알아보려고 합니다.
항상 iOS 프로젝트를 하면 테이블 뷰, 컬렉션 뷰를 사용하는 것이 제일 까다롭더라고요!
(저만 그런가요..)컬렉션 뷰와 테이블 뷰 셀들의 라이프 사이클을 알아봅시다 !!
UITableViewCell LifeCycle
우선 간단한 테이블 뷰를 만들어보겠습니다.
위와 같이 간단한 형태의 테이블 뷰를 만들었습니다.
그러고 나서 Cell들의 Cycle에 해당하는 Delegate, DataSource들을 구현해서 하나씩 찍어보려고 합니다.
extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { print("Will Display Cell : \(indexPath.row)") } func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { print("Did End Display Cell : \(indexPath.row)") } }
위와 같이 Delegate에서 willDisplay와 didEndDisplaying 함수에 print문을 찍어줄 것입니다.
extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell", for: indexPath) cell.textLabel?.text = "Cell \(indexPath.row)" print("cellForRowAt : \(indexPath.row)") return cell } }
DataSource는 필수 구현 함수인 numberOfRowsInSection과 cellForRowAt을 구현해줍니다.
ViewController에는 이 정도로 구현하고 Cell 파일로 들어갑니다.
override func awakeFromNib() { super.awakeFromNib() print("--------------awakeFromNib---------------") } override func prepareForReuse() { super.prepareForReuse() print("--------------prepareForeReuse---------------") } deinit { print("---------------deinit---------------") }
UITableViewCell 파일에는 awakeFromNib, prepareForReuse, deinit 함수들에 print문을 찍어줍니다.
그 후에 시뮬을 실행시켜주면 아래와 같이 콘솔 창에 찍힙니다.
Cell이 만들어질 때 awakeFromNib가 호출되고, 그 후에 cellForRowAt으로 셀을 만들어준 후 WillDisplay가 실행되는 것을 볼 수 있습니다.
awakeFromNib
셀이 생성된 후 초기화 작업을 해줍니다.
ViewController의 viewDidLoad처럼 Cell에는 awakeFromNib가 있다고 생각하면 편합니다.
즉, 초기화 작업을 해주는 함수입니다.tableView(_:cellForRowAt:)
UITableView의 특정 위치에 삽입할 Cell을 DataSource에 요청하는 함수입니다.tableView(_:willDisplay:forRowAt:)
UITableView의 셀을 그리기 전에 Delegate에 이 메시지를 전달하는 함수입니다.UITableViewCell Prefetching
그리고 pre-fetch이라는 것을 알아보기 위해 UITableViewDataSourcePrefetching을 구현해주도록 하겠습니다.
extension ViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { print("prefetch : \(indexPaths)") } func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { print("cancelPrefetching : \(indexPaths)") } }
prefetching 되면 print문이 찍히도록 구현했습니다. 다시 빌드를 해보도록 할게요.
시뮬이 동작했을 때 display 되는 셀까지 만들어진 후에 prefetch가 작동합니다.
14까지가 만들어지고, 15부터 prefetching 되는 것을 보니 화면에 보이는 셀 이후의 셀들을 미리 호출하는 것을 알 수 있습니다.
UITableViewDataSourcePrefetching
UITableViewDataSourcePrefetching 프로토콜은 iOS10부터 사용이 가능합니다.
디스플레이에 보여지는 셀 이외의 셀들의 정보를 미리 호출하여 데이터를 가져와줍니다.코드를 보면, 제가 두 개의 함수를 구현했습니다. 각각의 역할을 알아볼 건데요.
- tableView(_:prefetchRowsAt:)
필수로 구현해야 하는 함수입니다.
IndexPath에 해당하는 셀에 필요한 데이터를 미리 받아오는 함수입니다.
10개의 셀을 미리 받아옵니다.
(GCD나 비동기를 명시할 때 사용합니다.) - tableView(_:cancelPrefetchingForRowsAt:)
prefetch가 필요하지 않은 셀들의 prefetching을 취소해주는 함수입니다.
일반적으로 스크롤 방향이 바뀔 때 데이터 로딩이 덜 된 셀들을 취소할 수도 있고, 불필요한 작업을 최소화하여 CPU 작업 시간을 줄이는 함수라고 합니다.
UITableView Scrolling
지금까지는 스크롤이 되지 않았을 때를 알아보았는데요.
스크롤을 한번 해보겠습니다.
위 사진과 같이 스크롤을 했을 때 콘솔 창입니다.
셀들을 확인해보면 didEndDisplay가 호출되면서 콘솔에 찍히는 것을 볼 수 있습니다.
tableView(_:didEndDisplaying:forRowAt:)
Display 되던 셀이 사라지면 호출되는 함수입니다.그 후에 셀들을 쭉 보면 awakeForNib가 아닌 prepareForReuse가 호출되는 것을 확인할 수 있습니다.
prepareForReuse()
테이블 뷰 Delegate에 의해 재사용이 가능한 셀을 준비하는 함수입니다.
만약 셀이 재사용된다면 dequeueReusableCell 함수가 리턴되기 전에 호출됩니다.그 이유는 awakeForNib로 화면에 보이는 셀만 생성했습니다.
그 이후에는 재사용 큐에 넣어줬던 셀을 사용하기 때문에 셀을 다시 생성하지 않고 재사용하게 되는 것입니다.
즉, 재사용된 셀을 사용할 때는 prepareForReuse()가 호출됩니다.
UICollectionViewCell LifeCycle
컬렉션 뷰 셀의 라이프사이클은 여태까지 살펴봤던 테이블 뷰 셀의 라이프 사이클과 거의 99% 동일합니다.
시작은 dequeueReusableCell을 사용해서 셀을 생성하고, awakeForNib가 호출되면서 willDisplayCell이 호출됩니다.
스크롤을 할 경우 didEndDisplaying이 호출되면서 셀이 재사용 큐에 들어가게 됩니다.
prefetching 기술은 collectionView에도 적용할 수 있는데, pre-fetch로 인해 재사용되기 직전에 큐에 들어가지 않고 잠시 prefetching 되어있다가 바로 사용된다면 재사용을 적용하지 않고, prefetch 해서 사용하고 바로 사용되지 않는다면 셀이 재사용 큐에 들어간다고 합니다.
마무리
프로젝트를 하면서 테이블 뷰 셀 안에 컬렉션 뷰를 그려야 하는 작업이 있었습니다.
그때 셀의 재사용 때문에 애를 먹었었는데, 이번에 다시 한번 정리하니까 왜 며칠 동안 붙잡고 있었는지 약간 후회가 되네요 ㅠ^ㅠ
오늘도 포스팅 봐주셔서 감사합니다 :)
'iOS > iOS' 카테고리의 다른 글
[iOS] Unit Test에 대해 간단하게 알아보자 (0) 2020.09.25 [iOS] UI 개발 시 Code Base로 개발하기 (0) 2020.09.18 iOS의 데이터베이스 비교 (SQLite, Core Data, Realm) (0) 2020.08.07 CoreLocation 적용하기 (0) 2020.06.20 URL Session Tutorial: HalfTunes (0) 2020.05.31 - tableView(_:prefetchRowsAt:)