- 참고자료 : Apple Document
테이블뷰는 데이터를 앱에 표시할 수 있는 가장 기본적인 방법으로서, iOS개발에 중요한 요소중 하나이다.
- 기본 생성방법
- delegation 이란
UITableView에는 DataSource, Delegate 라는 대리자가 옵셔널로 생성되어 있다.
각각의 용도는 아래와 같다.
- DataSource : 테이븗뷰의 구성을 어떻게 할지 위임
- Delegate : 테이블뷰의 동작을 결정하는 걸 위임
- 아이폰 설정앱처럼 그룹화된 셀을 보여주고 싶다면 style에서 .grouped / insetGrouped 를 선택한다.
- 이 내용은 Section 구현에서 추가언급예정
- 셀을 스크롤하며 재활용해야한다면 cell도 등록해준다.
let tableView: UITableView = UITableView()
// let table = UITableView(frame: .zero, style: .plain)
// let table = UITableView(frame: .zero, style: .grouped)
// let table = UITableView(frame: .zero, style: .insetGrouped)addSubView(tableView)// frame으로 설정할 경우
tableView.frame = view.bounds// Constraint로 설정할 경우
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
table.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
table.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
table.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
table.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
])프로토콜을 채택하면 해당 프로토콜에서 미리 설정한 것들을 필수로 구현해야만 한다.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { }보통은 편의상 코드가독성을 위해 extension을 사용한다.
class ViewController: UIViewController { }
extension ViewController: UITableViewDelegate, UITableViewDataSource { }delegation이란 원래 해당 역할을 수행할 주체를 위임한다는 것이다.
그래서 ViewController 내부에서 tableView의 delegate를 self로 선언한다는 것은
해당 tableView의 여러 메서드들을 ViewController에 구현해서 처리하겠다는 말이다.
tableView의 위임자는 delegate와 dataSource가 있다.
tableView.delegate = self
tableView.dataSource = self만약 delegate 선언을 상단 프로퍼티의 클로저에 구현하고 싶다면 이렇게 선언한다.
lazy var tableView: UITableView = {
let tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
return tableView
}()- 여기선 10개의 셀에 "Hello world"를 보여주는 것으로 하드코딩
/// 테이블뷰 섹션 내부의 Row의 갯수를 선언하는 부분
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
/// cell이 어떻게 보여질지 세팅하는 부분
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// UITableViewCell 구현
let cell = UITableViewCell()
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
}- 시뮬레이터 다크모드전환 단축키:
Shift + Command + A
import UIKit
class ViewController: UIViewController {
let tableView: UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
/// 테이블뷰 섹션 내부의 Row의 갯수를 선언하는 부분
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
/// 테이블뷰의 cell이 어떻게 보여질지 선언하는 부분
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// UITableViewCell 구현
let cell = UITableViewCell()
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
}
}테이블뷰에서 가장 중요한 요소 중 하나이다.
테이블뷰는 스크롤할 정도로 여러개의 셀을 가지고 있을 때,
추가적으로 화면에 표시할 셀을 생성하게 되어있다.
그런데 매번 새로 생성하게 되면 자원을 낭비하기 때문에 사용하는 개념이 재사용이다.
메모리의 HEAP영역에 셀 관리용 Queue를 두고, 한번에 화면에 표시될 분량의 셀들을 이곳에 저장해둔다. 그리고 화면을 스크롤 할 때, Heap영역에 저장된 셀을 꺼내서(Dequeue) 사용하는 것이다.
이방법을 사용하게 되면 메모리를 보다 효율적으로 사용할 수 있다.
다만 기존 셀의 UI와 새롭게 나타나야할 셀과 다른 경우에 UI를 업데이트 하기위한 로직을 추가해야한다는 것을 유념하자.
셀을 사용하기 위해서는 미리 그 Queue에 넣을 셀을 등록해야한다.
이 때, 어떤 셀을 사용할 건지 해당 셀의 객체타입의 타입 (메타타입; ex UITableViewCell.self)과 해당 셀 구분에 사용할 Identifier를 입력해야한다.
이 과정은 스토리보드를 사용하는 경우에는 Cell에 Class를 지정하고 ID를 선언함으로 대체된다.
- UINib : 내가 사용할 테이블뷰셀 클래스의 메타타입
- 만약 커스텀 클래스를 사용한다면 해당 클래스의 메타타입을 넣어준다.
- forCellReuseIdentifier : 구분에 필요한 ID
// 재사용할 셀을 등록하는 메서드
func register(UINib?, forCellReuseIdentifier: String)
// 사용예
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// 커스텀 테이블뷰 셀인 경우
tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "cell2")UITableView는 reusableCell 큐에서 지정된 식별자(identifier)를 가진 셀을 "빼내어(dequeue)" 재사용하는 방식으로 작동한다. 이때 사용하는 메서드는 두가지가 있는데, 아래 메서드가 indexPath를 넣어서 명시적으로 설정하는 메서드기 때문에 이걸 이용하는 것을 선호한다.
- withIdentifier : 구분에 필요한 ID
- for : indexPath
func dequeueReusableCell(withIdentifier: String, for: IndexPath) -> UITableViewCell
// tableView의 DataSource 메서드
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
// 커스텀 클래스 인경우에는 반드시 커스텀 테이블뷰 셀로 타입캐스팅을 해준다.
// let myCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
// cell.mainImageView.image = UIImage(named:"test")
//
// return myCell
}
import UIKit
class ViewController: UIViewController {
let tableView: UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
/// 테이블뷰 섹션 내부의 Row의 갯수를 선언하는 부분
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 50
}
/// 테이블뷰의 cell이 어떻게 보여질지 선언하는 부분
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// UITableViewCell 구현
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
}
}- 240514: register, dequeue개념 수정