본문 바로가기

UIKit

[UIKit] UITableView의 indexPathForRow(at:) 오차에 대한 디버깅

반응형

최근 여러 가지의 Cell을 Generic을 활용하여 구성하는 방식을 사용하며 발생했던 문제에 대해 다루고자 합니다.

 

https://medium.com/chili-labs/configuring-multiple-cells-with-generics-in-swift-dcd5e209ba16

Configuring multiple cells with generics in Swift

iOS Developers spend most of their development time dealing with UITableView and UICollectionView. It’s quite straightforward when you need…

medium.com

현재 저희는 위 글을 참고, 커스텀하여 활용하고 있습니다.

다음에 커스텀한 내용에 대하여 다룰 예정이지만,, 관심 있으신 분들은 먼저 위 글을 보고 오시면 이해하시는데 도움이 될 것 같습니다.

 

간략하게 설명하자면, 보통 Cell의 타입에 따라 cellForRowAt 함수에서 Cell에 해당하는 뷰들을 불러오고, 그 뷰들에 맞게 data를 세팅해주는 방식을 사용합니다. 이 방식을 사용하게 되면, Cell을 사용하는 종류가 많아질수록 분기 처리해야 하는 부분이 많아지게 됩니다.

 

 

 


그 외에 다른 문제점들이 있다고 판단하여, data에 view를 설정할 수 있는 방식을 사용하게 되었습니다.

 

 

 

 

사용하는 이유는 여러가지가 있지만,

 

  1. 불필요한 분기처리를 줄이는 것
  2. 타입 캐스팅을 줄이는 것
  3. Cell이 Data Type에 종속적이지 않은 것

 

이 포함되어있다고 생각합니다. 따라서 TableView의 Delegate method인 tableView(_:didSelectRowAt:) 를 사용할 경우에 난처한 상황이 발생했습니다.

여러 개의 Cell을 처리하기 위해서는 Configurator를 다시 분기 처리, 타입 캐스팅을 해야 했으며, 타입이 같은 뷰가 있다면 뷰에 따른 분기 처리 또한 필요하게 되었습니다.
이와 같은 문제점을 해결하기 위해 Cell에 TapGestureRecognizer를 붙여 위임 처리를 하도록 진행했습니다.

긴 서두를 거쳐 돌고 돌아왔습니다. 이제 본론으로 들어가고자 합니다.

위임처리를 했지만, 선택된 Cell의 indexPath가 필요한 경우가 있었는데, indexPathForRow(at:) 를 활용하여 indexPath를 구할 수 있었습니다.

(해당 이슈 재현을 위해 top, bottom의 margin을 소수점 단위로 설정하여 진행했습니다.)

 

 

 

 

하지만 여기에서 문제가 생겼습니다. 간헐적으로 indexPath가 정상적으로 나오지 않고, 씹히는(?) 경우가 발생했습니다.

 

 

 

 

순서대로 선택한 Cell의 index path

 

 

 

 

해당 이슈는 Cell의 크기와 동일한 내부 커스텀 뷰의 zero 포인트로 index path를 구하는 과정에서 발생한 이슈라고 판단했고, 그 과정을 디버깅했습니다.

 

 

 

위와 같이 getIndexPath(from:) 메서드를 확장하여 테스트를 진행했습니다.

4~8 line : 메서드 내부에서 중첩 함수로 getCell(from:)을 정의했고, 이는 재귀 함수를 통해 TableViewCell을 받아오는 로직입니다.

10~14 line : view의 zero point로 indexPath를 구하는 과정입니다.

16~25 line : 실제 TableViewCell과 그 indexPath, CustomView와 그 indexPath를 비교하는 과정입니다.

 

결과 

 

 

 

 

 

 

 ...

 

 

 

 

 

 

 

결론

 

Cell 내부의 View를 Cell의 edge와 동일하게 constraint를 설정했지만, 계산하는 과정에서 오차가 발생한 것을 알 수 있었습니다.

let viewPoint = view.convert(view.center, to: tableView)

위와 같이 zero 지점이 아니라 view의 center지점으로 설정하면, 오차가 발생할 가능성이 줄어들 것이라고 생각합니다. (실제로 위의 케이스에서도 정상적으로 작동하는 것을 확인했습니다.)

UITableView 내부에서는 정확히 어떻게 처리하고 있을지는 모르겠지만, 오차에 대한 처리를 진행하고 있을 것이라고 예상이 되며, 따라서 tableView(_:didSelectRowAt:) 를 사용하는 것이 가장 안전하다고 할 수 있겠네요.

이 생각을 바탕으로 현재는 Configurator에 적용하여 사용하는 것을 검토하고 있습니다.

 

 

 

반응형