본문 바로가기

MOBILE/ios

[iOS] UITableViewController delegate method 모아보기

 UITableViewController 

: UIKit 에서 데이터를 리스트 형태로 보여주기에 적합한 view controller는 Table View Controller이다.

 

임시로 table view로 구현해본 list

위와 같이 데이터를 리스트 형태로 표현 가능하여 직관적으로 데이터의 목록을 볼 수 있다.

table view의 계층 관계는 다음과 같다.

테이블 뷰 컨트롤러 -> 테이블 뷰 -> 테이블 뷰 cell -> content view

이때 하나의 테이블 뷰에는 여러 개의 테이블 뷰 섹션이 있을 수 있다. 섹션은 그룹과 비슷하다.

 

 

이러한 table view controller 가 정의되어 있는 곳을 보면 다음과 같다.

 

 

UITableViewController 는 UIViewController를 상속받고 UITableViewDelegate, UITableViewDataSource 두 개의 프로토콜을 구현하고 있다. 각각 프로토콜의 역할은 다음과 같다.

 

UITableViewDelegate

: 테이블에서 발생하는 액션 및 이벤트와 관련된 메소드가 정의되어 있다.

 

UITableViewDataSource

: 데이터를 관리하고 cell을 준비하는 등 테이블을 구성하기 위해 필요한 메소드가 정의되어 있다.

 

UITableViewController는 델리게이트 패턴으로 동작한다. 즉 메소드를 오버라이딩 하는 것 만으로도 동작과 데이터에 대한 제어를 할 수 있다. 따라서 프로토콜을 직접 받아서 커스텀 클래스로 구현한다면 다음과 같이 속성을 프로토콜 구현 클래스 자신으로 지정해야 한다.

 

self.tableView.delegate = self
self.tableView.dataSource = self

 

ios는 table view의 data source 속성을 통해서 소스 프로토콜이 구현되어 있는 객체를 참조하고, 똑같이 델리게이트 속성을 통해서 델리게이트 프로토콜이 구현되어 있는 객체를 참조한다. 이 객체에 구현되어 있는 메소드를 찾아 호출하는 것이 델리게이트 패턴이다.

tableviewcontroller를 사용하면 이 속성을 자동으로 지정되기 때문에 설정할 필요가 없다.

 

프로토콜의 메소드는 엄청나게 많고 다양하다. 이러한 델리게이트 메소드들을 정리해보자.


UITableViewDataSource의 Instance methods

 

table view의 row, section number

tableView(_:numberOfRowsInSection:)

특정 section에 몇개의 행(cell)이 있는지 data source에게 알려준다.

data source는 이 메소드의 반환값을 구해서 cell을 생성한다.

 

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

Parameters

tableView: 어떤 table view 객체에 대해서 요청하는지

section: table view section에 대한 Int 정보

Return Value

section 안의 행의 수를 return 한다.

 

numberOfSections(in:)

table view에 몇개의 section이 있는지 data source에게 알려준다.

 

optional func numberOfSections(in tableView: UITableView) -> Int

Parameters

tableView: 어떤 table view 객체에 대해서 요청하는지

Return Value

table view 안의 section의 수를 return 한다.

Discussion

오버라이딩으로 구현하지 않는 경우, 1개의 section으로 자동 간주된다.


table view의 cell, Header, Footer

tableView(_:cellForRowAt:)

table view의 cell을 구현할 cell 정보를 return 한다. (required)

 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

Parameters

tableView: cell 정보를 요청하는 table view 객체

indexPath: table view의 특정 cell의 행에 대한 정보를 가지고 있는 IndexPath (어떤 행의 cell인지 이 정보로 판단 - indexPath.row)

Return Value

cell 객체인 UITableViewCell가 return 된다. 이는 특정 행에 대한 cell로 사용된다.

Discussion

table view cell에는 재사용 매커니즘이 사용된다.


재사용 메커니즘 (Reuse Mechanism)

: ios가 자랑하는 (ios의 최고 장점) 부드럽고 자연스러운 UI와 화면 전환 및 스크롤을 위해 사용되는 메커니즘 중 하나이다.

 

table view가 구현해야 하는 cell이 많다고 가정하자. 한 100개 정도. 이러한 cell을 한번에 만들어낸다면 분명 처리해야 하는 메모리도 많아지므로 부드러운 화면 움직임이 나타나기 어렵다. 그리고 가장 중요한 점은 100개의 cell이 화면에 한번에 보여지지도 않는다는 것이다. 따라서 굳이 많은 cell을 한번에 구현할 필요가 없다. 따라서 cell은 재사용 메커니즘에 의해 관리된다.

 

table view는 cell 객체를 data source에 요청하게 되고, data source는 이 메소드를 실행한다. 이때 data source는 table view의 재사용 큐(Reuse Queue)에서 사용 가능한 cell을 우선 검색한다. 있다면 queue에서 cell 객체를 꺼내고, 없다면 새로 생성한다.

사용자의 화면 스크롤로 인해 화면에 보이지 않는 cell 이 생기면 cell은 table view에서 제거된다.

하지만 cell 객체 자체는 사라지지 않고 재사용 큐에 추가되어 다음 사용 때 재활용 되기 위해 대기한다.

이것이 바로 재사용 메커니즘이다.

 

재사용 큐에 여러개의 cell이 있다면 어떤 cell을 반환해야 할까?

data source는 cell들에 재사용 식별자(Reuse Identifier)를 부여하여 cell을 구별한다.

 

다음과 같이  dequeueReusableCell(withIdentifier:for:) method를 통해서 재사용 큐에서 cell을 가져온다.

 

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)

    return cell
}

 

tableView(_:heightForRowAt:)

table view cell에 대한 높이를 설정한다.

 

optional func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat

Parameters

tableView: 대상이 되는 table view 객체

indexPath: 특정 row에 대한 정보를 담고 있는 IndexPath 객체

Return Value

cell의 높이 (floating point)

Discussion

ios에서 cell의 높이는 cell의 height 속성으로 결정되는 것이 아니라, 이 메소드의 반환값으로 처리되는 것이다.

 

tableView(_:titleForHeaderInSection:)

section의 헤더 title을 설정한다.

 

optional func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?

Parameters

tableView: header의 title을 설정할 table view 객체

section: table view의 어떤 section에 title을 설정할지

Return Value

title로 설정할 문자열을 return 한다. 이때 title이 없는 경우 nil을 반환할 수 있다.

Discussion

이 method는 좋지만 header title의 font와 style에 대해서는 커스텀 설정을 줄 수 없다. 따라서 따로 커스텀을 하고 싶을 경우 다른 delegate method를 사용해야 한다. 바로 밑에 나오는 tableView(_:viewForHeaderInSection:) 이다.

tableView(_:titleForHeaderInSection:), tableView(_:viewForHeaderInSection:) 모두 구현했을 경우 후자에게 우선순위가 부여된다.

 

tableView(_:viewForHeaderInSection:)

section의 header에 설정할 view를 반환한다.

 

optional func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?

 

Parameters

tableView: header의 title을 설정할 table view 객체

section: table view의 어떤 section에 titleView를 설정할지

Return Value

section에 설정하고 싶은 view면 뭐든지 가능하다. 예를 들어 UILabel, UIImageView 등등

Discussion

밑에 나오는 custom header의 높이를 계산하는 tableView(_:heightForHeaderInSection) method를 구현하지 않는 경우 자동으로 header의 높이를 계산한다. (또는 sectoinHeaderHeight 속성을 설정하면 된다)

 

tableView(_:heightForHeaderInSection:)

section header의 높이를 설정한다.

 

optional func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat

Parameters

tableView: header의 높이을 설정할 table view 객체

section: table view의 어떤 section에 titleView를 설정할지

 

Return Value

section의 header 높이를 floating point로 return 한다.

 

 

Header와 비슷하게 Footer는 뷰 밑~safe area 까지의 영역이 된다.

그때의 delegate method는 Header와 똑같이 동작한다.

tableView(_:titleForFooterInSection:)

: footer에 title만 설정할 때

tableView(_:viewForFooterInSection:)

: footer에 커스텀 뷰를 설정할 때


table view의 편집 기능 제공 여부

tableView(_:canEditRowAt:)

특정 row가 수정 가능한지 Bool type으로 return 한다.

 

optional func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool

 

Parameters

tableView: 대상이 되는 table view 객체

indexPath: 특정 row에 대한 정보를 담고 있는 IndexPath 객체

Return Value

indexPath로 접근한 row가 수정 가능하면 true, 아니면 false

Discussion

구현하지 않을 시, 편집 가능한 것으로 간주한다. 또한 수정가능한 row는 insert, delete control이 가능하다.

이때 editingStyle은 다음에 나오는 tableView(_:editingStyleForRowAt) 함수에 의해 결정된다.

 

 

tableView(_:editingStyleForRowAt:)

table view cell의 edit style을 결정한다.

 

optional func tableView(_ tableView: UITableView, 
   editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle

Parameters

tableView: 대상이 되는 table view 객체

indexPath: 대상이 되는 특정 row에 대한 정보를 담고 있는 IndexPath 객체

Return Value

indexPath로 접근한 row의 edit style

Discussion

구현하지 않을 시, UITableViewCell.EditingStyle.delete 가 기본 적용된다.

UITableViewCell.EditingStyle에는 3가지의 선택사항이 있다.

 

 

none: no edit style

delete: 삭제

insert : 추가

 

tableView(_:commit:forRowAt:)

table cell의 편집에 대한 코드를 구현한다.

 

optional func tableView(_ tableView: UITableView, 
                commit editingStyle: UITableViewCell.EditingStyle, 
               forRowAt indexPath: IndexPath)

Parameters

tableView: 대상이 되는 table view 객체

editingStyle: indexPath로 전달되는 row에 대한 편집 스타일 정보이다. 이때 가능한 경우는 .insert, .delete 두가지이다.

indexPath : 대상이 되는 특정 row에 대한 정보를 담고 있는 IndexPath 객체

Discussion

 사용자가 insert 또는 delete 버튼을 누를 시 table view는 data source의 이 메소드를 실행하고 변화를 commit 한다. (삭제 또는 추가에 대한 변화) data source는 내부적으로 insertRows(at:with:) , delete(at:with:) 함수를 불러 이를 처리한다.

ios에서 제공하는 cell을 옆으로 swipe 했을 때 보이는 delete 버튼 활성화를 위해서는 이 메소드를 반드시 구현해야 한다.

또한 이 메소드 안에서 setEditing(_:animated) 메소드를 불러서는 안되며, 대신 perform(_:width:afterDelay) 를 구현 가능하다.


table view의 cell 순서 변경

tableView(_:canMoveRowAt:)

table cell의 순서가 변경될 수 있는지 Bool type으로 return 한다.

 

optional func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool

Parameters

tableView: 대상이 되는 table view 객체

indexPath: 대상이 되는 특정 row에 대한 정보를 담고 있는 IndexPath 객체

Return Value

행이 움직일 수 있으면 true, 아닐 시 false

Discussion

 구현했을 경우 reordering control에 대한 show 여부를 결정할 수 있다. tableView(_:moveRowAt:to:)가 구현되어 있다면 reordering control이 이 메소드의 구현 여부와 상관없이 보이게 된다.

 

tableView(_:moveRowAt:to:)

table cell의 순서를 source에서 dest로 이동시킨다.

 

optional func tableView(_ tableView: UITableView, 
              moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)

Parameters

tableView: 대상이 되는 table view 객체

sourceIndexPath: 대상이 되는 특정 row의 원래 위치

 

destinationIndexPath: 대상이 되는 특정 row의 이동 목적지

Discussion

사용자가 sourceIndexPath에서 reordering control을 누를 시 UITableView object는 이 메소드를 data source에게 보낸다. (델리게이트 패턴이므로)