본문 바로가기

UIKIT

UICollectionReusableView와 UIView의 차이 + headerSection

UICollectionReusableView와 UIView의 차이

UICollectionReusableView

  • UICollectionView에서 재사용이 가능한 뷰를 위한 클래스입니다.
  • 주로 섹션 헤더, 섹션 푸터, 또는 커스텀 장식을 위한 뷰를 만들 때 사용됩니다.
  • 재사용 큐(reuse queue)를 활용하여 메모리 효율성을 극대화합니다.
  • UICollectionReusableView는 UICollectionView와 연동하여 동작하도록 설계되어 있습니다.
    • 예를 들어, 재사용 식별자(reuseIdentifier)를 통해 등록하고 dequeuing하는 메서드가 제공됩니다.

 

UIView

  • iOS에서 기본적으로 사용되는 뷰 클래스입니다.
  • 재사용 메커니즘이 없으므로, 메모리 관리와 재사용은 개발자가 직접 처리해야 합니다.
  • 기본적으로 뷰 자체를 재사용하는 컬렉션 뷰의 요구 사항을 만족시키지 못합니다.

 

등록 및 dequeue 메커니즘

  • UICollectionReusableView는 재사용 식별자(reuseIdentifier)를 통해 UICollectionView와 등록 및 dequeuing 작업을 수행합니다.
collectionView.register(
	MyHeaderView.self, 
    forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, 
    withReuseIdentifier: "header")

 

func collectionView(_ collectionView: UICollectionView, 
	viewForSupplementaryElementOfKind kind: String, 
    at indexPath: IndexPath) -> UICollectionReusableView {
    
    let header = collectionView.dequeueReusableSupplementaryView(
        ofKind: UICollectionView.elementKindSectionHeader,
        withReuseIdentifier: "header",
        for: indexPath
    ) as! MyHeaderView
    header.configure(with: data) // 헤더 구성
    
    return header
}

 

  • UICollectionReusableView는 UICollectionViewCompositionalLayout에서도 섹션 헤더/푸터 역할에 완벽히 맞춰 작동합니다.
  • 헤더를 정의할 때, 다음처럼 NSCollectionLayoutBoundarySupplementaryItem에 등록합니다:
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(50))
let header = NSCollectionLayoutBoundarySupplementaryItem(
    layoutSize: headerSize,
    elementKind: UICollectionView.elementKindSectionHeader,
    alignment: .top
)

 

  • 섹션 헤더/푸터로는 반드시 UICollectionReusableView를 사용해야 합니다.
  • 이유:
    1. 재사용 메커니즘: 메모리 효율성 극대화.
    2. 데이터와 연동: 데이터 소스와 잘 통합되어 데이터 설정이 용이.
    3. 레이아웃 통합: UICollectionViewCompositionalLayout과 완벽히 호환.
    4. 기능 최적화: 헤더/푸터의 역할에 맞는 메서드와 구조 제공.
  • UIView는 이러한 작업에 적합하지 않으며, 섹션 헤더/푸터의 특성상 재사용이 중요하기 때문에 반드시 UICollectionReusableView를 사용해야 합니다.
func createDataSource() {
        dataSource = UICollectionViewDiffableDataSource<TMDBData, MainResults>(collectionView: collectionView) {
            collectionView, indexPath, model in
            switch self.combineSection.combineTMDB[indexPath.section].type {
            case .topRatedMovie:
                return self.configure(TopRatedCell.self, with: model, for: indexPath)
            default:
                return self.configure(TodayCollectionViewCell.self, with: model, for: indexPath)
            }
        }
        
        dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in
            guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: SectionHeader.reuseIdentifier, for: indexPath) as? SectionHeader else { return nil}
            
            guard let firstApp = self?.dataSource?.itemIdentifier(for: indexPath) else { return nil }
            guard let section = self?.dataSource?.snapshot().sectionIdentifier(containingItem: firstApp) else { return nil }
            
            switch section.type {
            case .noewPlayingMovie:
                sectionHeader.title.text = section.type?.rawValue
                sectionHeader.subTitle.text = "상영중인 작품"
            case .popularMovie:
                sectionHeader.title.text = section.type?.rawValue
                sectionHeader.subTitle.text = "선호하는 작품"
            case .topRatedMovie:
                sectionHeader.title.text = section.type?.rawValue
                sectionHeader.subTitle.text = "작품 순위"
            case .upcomingMovie:
                sectionHeader.title.text = section.type?.rawValue
                sectionHeader.subTitle.text = "개봉 예정 작품"
            default:
                return nil
            }
            return sectionHeader
            
        }
    }


위의 함수에서 각 sectionHeader를 설정하는 부분은 UICollectionView의 섹션 헤더를 구성하기 위한 로직입니다. 헤더 뷰는 각 섹션에 대한 제목 및 부제목과 같은 추가 정보를 표시하기 위해 사용됩니다. 이 과정은 Diffable Data Source의 supplementaryViewProvider를 통해 구현되었습니다.

 

 

supplementaryViewProvider 등록

dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in
    ...
}
  • supplementaryViewProvider섹션 헤더 또는 푸터와 같은 추가 뷰를 생성하고 반환하는 클로저입니다.
  • collectionView: 헤더나 푸터가 표시될 컬렉션 뷰.
  • kind: Supplementary View의 종류. 보통 UICollectionView.elementKindSectionHeader로 섹션 헤더를 나타냅니다.
  • indexPath: 헤더가 배치될 섹션의 IndexPath.

 

헤더 뷰 재사용

guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(
    ofKind: kind,
    withReuseIdentifier: SectionHeader.reuseIdentifier,
    for: indexPath
) as? SectionHeader else { return nil }
  • dequeueReusableSupplementaryView: 재사용 가능한 헤더 뷰를 큐에서 가져옵니다.
  • SectionHeader.reuseIdentifier: 헤더 뷰의 재사용 식별자입니다. SectionHeader는 UICollectionReusableView를 상속한 클래스입니다.
  • 가져온 뷰를 SectionHeader로 다운캐스팅합니다.

 

현재 섹션 데이터를 가져오기

guard let firstApp = self?.dataSource?.itemIdentifier(for: indexPath) else { return nil }
guard let section = self?.dataSource?.snapshot().sectionIdentifier(containingItem: firstApp) else { return nil }
  • itemIdentifier(for:): 현재 indexPath에 해당하는 아이템(셀)을 가져옵니다. 이는 MainResults 타입의 데이터를 반환합니다.
  • sectionIdentifier(containingItem:): 위에서 가져온 MainResults가 속한 섹션(TMDBData)을 가져옵니다.
  • 결과적으로, section에는 현재 섹션(TMDBData)이 담기며, 이를 통해 해당 섹션의 type에 접근할 수 있습니다.

 

헤더 뷰 설정

switch section.type {
case .nowPlayingMovie:
    sectionHeader.title.text = section.type?.rawValue
    sectionHeader.subTitle.text = "상영중인 작품"
case .popularMovie:
    sectionHeader.title.text = section.type?.rawValue
    sectionHeader.subTitle.text = "선호하는 작품"
case .topRatedMovie:
    sectionHeader.title.text = section.type?.rawValue
    sectionHeader.subTitle.text = "작품 순위"
case .upcomingMovie:
    sectionHeader.title.text = section.type?.rawValue
    sectionHeader.subTitle.text = "개봉 예정 작품"
default:
    return nil
}
  • section.type: 현재 섹션의 타입입니다. 이는 API 호출 시 설정된 SectionType 열거형 값을 나타냅니다.
  • 각 타입에 따라 헤더 제목(title)과 부제목(subTitle)을 설정합니다.
    • rawValue: 열거형 타입의 문자열 값으로, 섹션의 이름을 표시하는 데 사용됩니다.
    • subTitle: 섹션에 대한 추가 설명입니다.
  • 예를 들어, 타입이 .topRatedMovie라면 헤더는 다음과 같이 설정됩니다:
    • 제목: "Top Rated Movie" (rawValue)
    • 부제목: "작품 순위"

'UIKIT' 카테고리의 다른 글

ViewModel을 사용하는 목적  (0) 2025.01.08
UITabBarAppearance  (0) 2025.01.05
UIFontMetrics  (0) 2025.01.05
키보드 내리기  (0) 2024.12.27
UICollectionView의 셀 크기를 동적으로 정사각형으로 조정하려면?  (0) 2024.12.22