Collection View
를 표현하려면 세 가지가 꼭 필요하다.
바로 Data
, Presentation
, Layout
이것만 기억하자.
Swift
에서 Collection View
를 구현할 때 Data
, Presentation
, Layout
세 가지 요소가 필요한 이유는 이들 각각이 Collection View
의 다른 중요한 측면을 담당하기 때문이다.
Data (데이터)
Collection View 는 여러 개의 항목을 화면에 표시하는 UI 컴포넌트이다. 이 항목들 각각에 대한 정보는 데이터를 통해 제공되는데, 이 데이터가 있어야 어떤 항목을 표시할지 알 수 있다. 예를 들어, 사진 갤러리 앱이라면 각각의 사진이 데이터가 되고, 데이터를 정의하지 않으면 Collection View 는 무엇을 표시해야 하는지 모른다.
어떠한 데이터가 몇 개가 있는데?
" 라는 말이다.Presentation (표현, 표시 방식)
데이터는 단순히 값일 뿐이므로 이를 화면에 어떻게 보여줄지 결정하는 것이 필요하다. Presentation 은 데이터를 기반으로 각 Cell 을 어떻게 표현할지를 결정하는데, 예를 들어 텍스트만 표시할지, 이미지를 함께 표시할지, 각 항목의 크기나 모양을 어떻게 할지를 정하는 것이다. 이를 위해 Collection View 는 주로 UICollectionViewCell 을 사용해 데이터를 시각적으로 표현한다.
그 데이터를 셀에 어떻게 표현할 건데?
" 라는 말이다.Layout (레이아웃)
Collection View 는 여러 개의 항목을 한 화면에 보여주기 때문에, 이 항목들이 어떤 방식으로 배열될지 결정하는 것이 필요하다. 이 부분을 담당하는 것이 Layout 인데, Layout 은 각 항목의 위치와 크기를 결정하며 UICollectionViewLayout 을 통해 제어된다. 기본적으로는 UICollectionViewFlowLayout 이 자주 사용되는데, 이는 항목을 격자 형태로 나열하거나 세로 또는 가로로 흐르듯 배치할 수 있게 해준다.
각 셀들의 레아이웃을 어떻게 할 건데?
" 라는 말이다.따라서, 이 세 가지가 모두 있어야 Collection View는 데이터를 받아 적절한 셀로 표시하고, 화면에 보기 좋은 방식으로 배열할 수 있다. 데이터가 없으면 표시할 내용이 없고, Presentation이 없으면 어떻게 보여줄지 알 수 없으며, Layout이 없으면 항목이 화면에 어떻게 배치될지 결정할 수 없기 때문이다.
Data
와 Presentation
을 지정하기 위에선 데이터 소스라는 프로토콜을 따르게 해야하는데 그게 바로 나라고 알려줄 필요가 있다.
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
collectionView.delegate = self
}
위 코드를 쉽게 풀어보자.
맨 윗줄은 지난 블로그에서 봤듯 viewDidLoad는 뷰가 준비될 때 한 번 호출되어 초기 설정을 수행하고 뷰 컨트롤러가 제대로 동작할 수 있도록 준비를 하는 역할이다. 자연스럽게 넘어가자.
collectionView.dataSource = self
collectionView.delegate = self
viewDidLoad()
에서 dataSource
와 delegate
를 self
로 설정하면, 현재의 뷰 컨트롤러가 해당 프로토콜을 준수하고 있다는 것을 알려주는 것이다. 그러나 이 설정만으로는 부족하다. UICollectionViewDataSource
와 UICollectionViewDelegate
의 요구사항을 충족시키기 위해 반드시 extension
을 통해 관련 메서드를 구현해야 한다.
extension
을 사용하여 코드를 작성하는 이유는 코드의 가독성과 모듈화를 위해서 인데, UIViewController
본체에서 직접 모든 프로토콜 메서드를 구현할 수도 있지만 이를 extension
으로 분리하면 각각의 역할이 명확해지고 코드가 더 깔끔해진다.
따라서, extension
을 통해 UICollectionViewDataSource
와 UICollectionViewDelegate
의 메서드를 구현해야 Collection View
가 정상적으로 동작 되는 것이다.
모듈화 : 모듈화란 복잡한 코드를 작게 나눠서 관리하기 쉽게 만드는 것이다. 마치 레고 블록을 여러 개로 나누어서 각각을 따로 조립한 후, 필요할 때 그 블록들을 합치는 것과 같다고 보면 된다. 코드를 기능별로 작은 조각들로 나누면 각 조각을 따로 수정하거나 재사용할 수 있어서 관리가 편해진다. 쉽게 말하자면 한꺼번에 모든 걸 처리하지 않고, 작은 단위로 나눠서 처리하는 것이 모듈화이다.
모듈화를 알게되고 나니 객체지향프로그래밍과 유사한 느낌이 들었다. 객체지향 프로그래밍에서 각 객체를 모듈처럼 독립된 단위로 볼 수 있기 때문이다. 하지만 모듈화
는 코드의 물리적 구조
에 더 가깝고, 객체지향은 프로그램
은 설계 철학
에 더 가깝다.
extension
은 Swift에서 기존 클래스
, 구조체
, 열거형
또는 프로토콜
의 기능을 확장할 수 있도록 해주는 기능이다. 이를 통해 새로운 메서드
, 속성
, 초기화 메서드
등을 추가할 수 있고, 기존 코드에 직접적으로 수정하지 않고도 원하는 기능을 확장할 수 있기 때문에 코드의 유연성과 재사용성을 높여준다.
간단히 말해서, extension
은 기존에 정의된 타입에 새로운 기능을 추가할 수 있는 방법이다.
extension
은 이미 만들어진 물건에 새로운 기능을 추가하는 것이라고 생각하면 된다. 예를 들어 스마트폰에 기본적으로는 전화 기능과 문자 기능만 있다고 가정하자. 그런데 카메라 기능이나 음악 재생 기능을 추가하고 싶을 때, 스마트폰 자체를 바꾸지 않고 새로운 기능을 추가하는 방법이 있다면 편리할 것이다. 이게 바로 extension
이다. 스마트폰(기존 클래스)
에 새로운 앱(기능)
을 설치해서 추가하는 것처럼, Swift에서도 이미 만들어진 클래스나 구조체에 새로운 기능을 extension
으로 더할 수 있다.
이렇게 기존 코드를 건드리지 않고도 기능을 추가할 수 있다는 점이 extension
의 중요한 역할이다. 예를 들어, 기본 숫자 타입 Int
에 새로운 기능을 추가하고 싶다면 extension
을 통해 간단히 추가할 수 있다.
extension Int {
func squared() -> Int {
return self * self // 4 * 4
}
}
let number = 4
print(number.squared()) // 출력: 16
위 예시에서는 원래 Int 타입에 squared()라는 기능 ( 숫자를 제곱하는 함수 ) 을 추가한 것인데, extension을 통해 Int 타입을 수정하지 않고도 새로운 기능을 넣은 것이다.
모듈화
: 코드를 논리적으로 나누어 가독성을 높인다.유연성
: 외부 라이브러리나 시스템 클래스를 수정하지 않고도 기능을 확장할 수 있다.프로토콜 준수
: 기존 타입이 특정 프로토콜을 따르도록 하고, 필요한 메서드들을 따로 구현할 수 있다.따라서 extension
은 코드를 더 간결하고 유지보수하기 쉽게 만들어주는 아주 스윗한 기능 같은 것이라 보면 된다.
강의에서는 딥하게 이해 할 필요 없고 '이런 것이 있다~' 정도로만 알고 있어도 된다고 하셨는데, 공부하다보니 기록해놓고 가끔씩 찾아보면 좋을 것 같아 이렇게 작성해 보았다.
덕분에 dataSource
와 delegate
에 뜬금없이 self
는 왜 들어갈까라는 궁금증이 해소되었고, 더불어 extension
까지 같이 공부할 수 있어서 즐겁게 검색했던 시간이었지 않나 싶다. 이렇게 이론적으로는 재미있게 잘 배웠는데 막상 코드를 작성할 때 바로 바로 나올 수 있을지가 관건이지만, 공든 탑이 무너지랴. 인내심을 가지고 차근 차근 공들여 쌓아보자.