안녕하세요. 오늘은 앱 개발 하다가 다시 한번 prepareForReuse()의 중요성을 깨닫고 개념과 제가 마주한 에러를 해결한 경험을 소개하려고 합니다.
(23.07.23)재사용 큐 탐구 포스트 링크
1. prepareForReuse()란?
컬랙션 뷰를 사용할 때, 새로운 cell을 보여줄 때마다 특정 데이터를 바탕으로 cell 인스턴스를 만드는 것은 메모리 사용량이 많아집니다.
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: MyCell.id,
for: indexPath) as? MyCell
else {
return .init()
}
그러기에 컬랙션 뷰를 만들 때 재사용하고 싶은 cell을 등록하고 cellForRowAt에서 위의 코드처럼 재사용큐에서 화면에 보여질 특정 cell을 꺼내옵니다. 재사용큐를 사용하므로 메모리 사용을 최적화 할 수 있습니다.
그리고 collectionView는 dequeueReusable queue에서 cell을 꺼내서 화면에 보여주기 전에!!! prepareForReuse() 함수를 실행시켜줍니다. 기본적인 prepareForReuse()함수 내부는 구현된 기능이 없습니다. 그렇지만 위 정의와 같이 UICollectionVIewCell타입인 특정 커스텀 cell에서 이 메서드를 override해서 원하는 내용을 초기화 하거나, 특정 UI를 숨겼다가 보여주거나, 속성을 변경하거나 업데이트하거나 등의 작업을 미리 준비할 수 있습니다. ( 화면에 보여지기 전에 꽃단장..)
1. prepareForReuse은 언제 사용해야 하는가?
예전에 인스타그램 클론으로 개발할 때 Notification 뷰의 cell에 대한 vm을 combine을 통해 바인딩해서 특정 cell의 데이터를 받아온 적이 있습니다. 내 앱에서 발생하는 문제가 없겠지 하고 모든 이상한 터치들을 했는데 정말 신기하게도 에러가 있었습니다.(바인딩 중첩 주제) 이 덕에 cell에서 Combine으로 바인딩 할 때는 정말 조심해야 겠다는 생각이 들었고 prepareForReuse()의 개념에 대해 알게 되었습니다. ( prepareForReuse() 구현할 때 cell에서 바인딩 중이었던 subscription을 전부 해제해야 이와같이 바인딩 중첩 발생이 안됩니다.)
이번에 개발하게된 스터디 매칭 앱에서 회원가입 화면의 일부 구성입니다.
이를 실험삼아 개발을 해봤습니다. 페이지컨트롤러를 사용해볼까 하다가 그냥 컬랙션 뷰로 최대한 재사용하기 쉽게 UILabel + UITextField의 구성으로 cell을 구현했습니다. ( SignUpViewCell ) 안애 UILabel + UITextField 두개의 컴포넌트가 있습니다. 그리고 각각은 cellForRowAt()함수 호출시 데이터를 할당했습니다.
우왓!! 그리고 또 새로운 이슈를 발견하게 되었습니다.
분명히 cell 안에 있는 subview인 textifeld의 text는 ""로 초기화를 했음에도..... 이전에 textField에 입력했던 값이 입력되어있었습니다. 그리고 특정 숫자 이상의 입력을 이상을 해야만 풀리는 '다음' 버튼이 자동으로 풀려있었습니다.... ( 대박 ) 코드가 잘못 입력됬나 30분동안 정독했는데.. (문제x)
이 cell은 마지막 cell이었고 이전에 입력한 텍스트가 남아있는 이유는 컬랙션 뷰의 재사용 메커니즘과 관련이 있기 때문입니다. 위에서 언급했지만, 셀을 효율적으로 재사용하기 위해 스크롤 될 때!! 화면에 보이지 않는 cell을 재사용합니다. 화면 영역에서 사라진 cell은 재사용 큐에 들어가고, 다시 보여질 때 꺼내오는...
이런 경우 때문에 이전에 입력한 텍스트필드가 다른 cell로 이동하면서 그대로 남아있는 경우가 발생된 것입니다. ( 컬랙션 뷰 특정 section에서 cell은 여러개를 등록해서 사용하는게 아니라 UILabel + UITextField 두개 (layout까지 같은 컴포넌트를 재사용하기 때문에 ..)
이를 해결하기 위해서는 사전에 스크롤로 인해 화면에 보여질 cell들을 어떻게 화면에 보여줄 것인지 prepareForReuse() 함수를 오버라이딩해서 특정 cell이 화면에 보여지기 위한 준비를 하면 됩니다.
저의 경우 기존에 bind된 subscriber를 취소하고 재등록시켰습니다. 그리고 버튼의 상호작용 false + 상호작용안될 때의 컬러 등등... 으로 cell이 재사용 큐에서 꺼내지기 전에 초기화 해야할 것들을 초기화 해줬습니다.
이번기회로 prepareForReuse()가 얼마나 중요한지 다시 한번 알게 되는 계기가 되었습니다. ( 이전에 텍스트필드에 입력된 값들도 재사용될 때 가져와질지 정말 몰랐는데 이번에 알게 되서 신기하네요.)
References:
https://developer.apple.com/documentation/uikit/uicollectionreusableview/1620141-prepareforreuse/
https://github.com/SHcommit/LearnMoreSwiftInUdemy/issues/30
'iOS > Deep dive!!!' 카테고리의 다른 글
[iOS] UITextField 입력시 자동으로 키보드 띄우기, 키보드 위에 버튼 올리기 +_+ | InputAccessoryView (1) | 2023.05.30 |
---|---|
[iOS] UITextField placeholder 색 변경하는 방법 (2) | 2023.05.30 |
[iOS] UITextField 비밀번호 입력시 문자 가리는 방법 | Strong Password 경고 (0) | 2023.05.29 |
[Swift] 네비게이션 바 커스텀으로부터 살아남기.. UIBarButtonItem (0) | 2023.05.16 |