Skip to content

Latest commit

 

History

History
305 lines (206 loc) · 9.12 KB

File metadata and controls

305 lines (206 loc) · 9.12 KB

UITableView - 기본 UITableView 생성

테이블뷰는 데이터를 앱에 표시할 수 있는 가장 기본적인 방법으로서, iOS개발에 중요한 요소중 하나이다.

이해하면 좋은 것

  • 기본 생성방법
  • delegation 이란



두 개의 Delegation

UITableView에는 DataSource, Delegate 라는 대리자가 옵셔널로 생성되어 있다.
각각의 용도는 아래와 같다.

  • DataSource : 테이븗뷰의 구성을 어떻게 할지 위임
  • Delegate : 테이블뷰의 동작을 결정하는 걸 위임

Step1. TableView 선언하기

Property

  • 아이폰 설정앱처럼 그룹화된 셀을 보여주고 싶다면 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)



View에 추가

addSubView(tableView)



frame 혹은 제약조건 세팅

// 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),
])



TableView Protocol 채택

프로토콜을 채택하면 해당 프로토콜에서 미리 설정한 것들을 필수로 구현해야만 한다.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { }

보통은 편의상 코드가독성을 위해 extension을 사용한다.

class ViewController: UIViewController { }

extension ViewController: UITableViewDelegate, UITableViewDataSource { }



TableView Delegate 선언

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
}()



TableView Delegate 메서드 세팅

  • 여기선 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
스크린샷 2023-01-28 오후 3 13 58



현재까지의 전체코드

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")



dequeue하여 재사용할 셀 선언하기

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
}



현재까지의 작업화면

스크린샷 2023-01-28 오후 3 13 58



전체코드

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
    }
}



HISTORY

  • 240514: register, dequeue개념 수정