[UIKit] collectionView 델리게이트 활용 시 주의사항
최근 프로젝트를 진행하다 컬렉션뷰의 셀에 레이아웃이 적용이 안되는 상황을 맞이했다. sizeForItemAt 델리게이트 메서드를 extension에서 구현을 하고 사이즈를 맞췄는데, 예상대로 움직이지 않았다.
image 사이즈가 45인데, 뷰 디버거를 활용해서 확인해보니, 외부에 선이 그어져있었고, 셀 자체의 크기가 50으로 설정이 되어 있는 것이다. width 45, height 65로 해서 정확히 사이즈를 맞춰놓았다고 생각했는데, 왜 안맞지? 라고 생각하고 있었다.
그러다 extension을 다시 보게되었는데, Delegate 설정에 문제가 있지 않을까 했다.
extension SelectBoardingCrewModalViewController: UICollectionViewDelegate {
func collectionView(
_ collectionView: UICollectionView,
numberOfItemsInSection section: Int
) -> Int {
if collectionView == selectBoardingCrewModalView.selectedCrewCollectionView {
return 25
} else {
return 28
}
}
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
return CGSize(width: 45, height: 65)
}
// 셀 간 최소 간격
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int
) -> CGFloat {
return 20
}
}
팀원 중 한명이 구현한 코드를 긁어왔었는데, UICollectionViewDelegateFlowLayout을 채택했었는데, 그냥 UICollectionViewDelegate를 써도 실행이 되길래 놔뒀었다. 그래서 다시 FlowLayout을 붙여줘보았다.
바로 되었다. 레이아웃 적용이 잘 된 것이다.
그래서 여기서 의문이 생겼다. 왜 그냥 Delegate를 썼어도 됐을까?
두 개의 델리게이트는 어떤 차이가 있을까?
상호간에 어떤 관계가 있기에 실행이 된 것일까?
1. 두 델리게이트의 차이
UICollectionViewDelegate와 UICollectionViewDelegateFlowLayout은 둘 다 UICollectionView의 동작을 컨트롤하고 사용자 상호작용을 처리하는 데 사용되는 프로토콜이다. 그러나 두 프로토콜 간에 몇 가지 중요한 차이가 있다.
1) UICollectionViewDelegate
- 이 프로토콜은 컬렉션 뷰의 다양한 이벤트 및 동작을 처리하기 위한 기본적인 메서드를 제공한다.
- 주요 메서드 중 하나는 **collectionView(_:didSelectItemAt:)**로, 셀이 선택되었을 때 호출된다. 이를 통해 사용자가 셀을 선택했을 때 원하는 동작을 수행할 수 있다.
- 컬렉션 뷰의 다른 동작 관련 이벤트를 처리하기 위한 메서드도 포함된다. 예를 들어, 셀을 이동하거나 삭제하는 동작을 처리할 수 있다.
2) UICollectionViewDelegateFlowLayout
- 이 프로토콜은 UICollectionViewDelegate의 서브 프로토콜로, 컬렉션 뷰의 레이아웃과 아이템 크기를 조절하는 메서드를 추가로 제공합니다.
- 주요 메서드 중 하나는 **collectionView(_:layout:sizeForItemAt:)**로, 각 셀의 크기를 동적으로 조절할 수 있습니다. 이를 통해 서로 다른 크기의 셀을 가진 레이아웃을 만들 수 있습니다.
- 다른 메서드로는 각 섹션의 여백(sectionInset), 헤더와 푸터의 크기(referenceSizeForHeaderInSection 및 referenceSizeForFooterInSection)를 조절하는 메서드도 제공됩니다.
요약하면, UICollectionViewDelegate는 컬렉션 뷰의 이벤트 처리와 동작 관리에 사용되며, UICollectionViewDelegateFlowLayout은 아이템의 크기 및 레이아웃 관련 작업에 특화된 프로토콜이다. 필요에 따라 두 프로토콜을 함께 사용하여 컬렉션 뷰의 동작 및 레이아웃을 세밀하게 제어할 수 있다.
2. 두 델리게이트의 관계
오케이. 하나는 셀 자체의 동작에 관련된 것이고, 하나는 FlowLayout에 관련된 것이다.
자세히 공식문서도 살펴보고, Xcode에서 커맨드를 눌러서 정의된 프로토콜을 살펴도 보았다.
@MainActor public protocol UICollectionViewDelegateFlowLayout : UICollectionViewDelegate {
@available(iOS 8.0, *)
optional func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize
...
}
그렇다. FlowLayout은 Delegate를 채택했다. 그래서 sizeForItemAt은 FlowLayout을 채택했을 때만 동작해야 한다.
하지만 Delegate만 채택해도 된다. 그것은 왜인가?
생각해보니... 당연한 것이었다.
ColletionViewDelegate에는 없는 메서드지만, extension에서 구현을 한다면, 새로운 메서드로 정의될 것이지만, 제대로 기능은 안하게 되는 것이다. 말 그대로 껍데기만 비슷해보이는 collectionView function이 구현되어 버리는 것이다. 델리게이트 패턴이 적용이 안되는 것이다.
다만, FlowLayout을 채택해도, 거기에 없는 collectionView(_:didSelectItemAt) 메서드를 사용해도 되는 이유는 FlowLayout이 UIColleciontViewDelegate 패턴을 채택했기 때문에, 사용할 수 있는 것이다.
상속... 아니 채택과 준수에 대한 개념이 제대로 되어 있지 않았기에 이런 실수를 한 것이다. 또한 공식 문서를 잘 읽어보고, 거기에 있는 메서드인지를 확인하고 나서 제대로 구현을 해야 하는것을 알게 되었다.
두 가지 깨달음을 얻은 UICollectionViewDelegate 구현이었다. 또한 여러 델리게이트 관계를 파악하고 구현을 해야겠다는 다짐을 하였다.
'iOS' 카테고리의 다른 글
[iOS] CoreData Attribute 변경 시 나타나는 Migration 문제 해결(code=134140) (1) | 2024.01.07 |
---|---|
[Swift] init과 Conveience init 그리고 ? (0) | 2023.10.14 |
[Xcode] The file “.swiftlint.yml” couldn’t be opened because you don’t have permission to view it. (0) | 2023.10.07 |
[UIKit] 그라데이션 라인 TableViewCell에 적용하기 (1) | 2023.10.06 |
[App Store] 앱 배포를 위한 과정 (0) | 2023.07.09 |
댓글