SSAC_iOS_Day 10 | TIL

린다·2021년 10월 12일
0

SSAC_iOS_Dev

목록 보기
6/33
post-thumbnail

👩‍💻 수업

📂 UITableViewController

  • ViewController vs TableViewController
    : Root View가 UIView, TableView로 서로 다르다.
  • TableViewController는 View 안에 컴포넌트를 자유롭게 넣어서 구성하기 어렵다. 자기 자신이 화면을 구성하는 것이 아니라 TableViewCell을 통해서 화면을 구현하기 때문에.
  • TableViewController를 사용하지 않고 UIViewController 안에 테이블뷰를 넣는 경우에는 UI컴포넌트도 마음대로 어느정도 추가할 수 있고 테이블뷰도 원하는대로 조절해서 사용이 가능하다.

📂 TableView

Table View의 필요성

  • 반복적인 디자인과 코드
  • 어려운 스크롤 구현
    ➡️ 반복적이고 많은 데이터를 간단하게 표현할 수 있는 방법

Table View의 구성

Cell + Section ➡️ Table View

Cell

  • System : 애플이 미리 만들어준 디자인, Basic, Subtitle, Right Detail, Left Detail
  • Custom
  • Cell content / Accessory View
  • Editing Control / Cell Content / Reordering Control

Table View

  • Content: Dynamic, Static
    - Static: 고정된 부분 (ex. 환경설정 메뉴)
    - Dynamic: 사용자에 따라 다르게 제공되는...
  • Header: 테이블뷰 윗 부분(ex. 인스타 스토리 부분)
  • Style: Inset Grouped(iOS15의 default), Plain, Grouped

Section
Cell을 그룹화할 수 있음! 이 앞에 붙는 타이틀이 섹션이라고 보면 됨~

  • System
  • Custom

Dynamic Prototypes vs Static Cell

  • Dynamic Prototypes: 코드로 구현해줘야함
  • 시뮬레이터로 바로 확인하고 싶다(코드없이) → Static Cells (사람에 따라 보여지는 항목이 모두 동일해서~)

📂 Table View 구현

1. 셀의 갯수: numberOfRowsInSection (필수)

테이블뷰가 몇 개의 셀로 구성되어 있는지 우리에게 알려주는 역할이 아니라, 몇 개의 셀을 생성해야 할지 iOS 시스템에게 알려주기 위해 작성

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return section == 0 ? 2 : list.count
    }

2. 셀의 디자인 및 데이터 처리: cellForRowAt (필수)

씬에 표현해야 할 셀의 수만큼 반복적으로 호출

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "memoCell") else {
            return UITableViewCell()
        }
        
        // 섹션에 따라 다른 디자인
        if indexPath.section == 0 {
            cell.textLabel?.text = "첫번째 섹션입니다 - \(indexPath)"
            cell.textLabel?.textColor = .brown
            cell.textLabel?.font = .boldSystemFont(ofSize: 15)
        } else {
            cell.textLabel?.text = list[indexPath.row]
            cell.textLabel?.textColor = .blue
            cell.textLabel?.font = .italicSystemFont(ofSize: 13)
        }
        
        return cell
    }

3. 셀의 높이(heightForRowAt) (옵션)

➡️ 명확하게 명시하는 것이 좋다.

코드로 확실히 구현해주는 편
고정으로 설정할 수도 있고, 디바이스별로 높이 기준으로 20% 높이를 주고싶어~ 도 가능

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// 섹션별로, 행 번호대로 높이를 조절해줄 수 있음
        return indexPath.row == 0 ? 44 : 80
    }

4. 섹션의 수: numberOfSections(default: 1) (옵션)

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

5. 섹션 타이틀: titleForHeaderInSection

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "섹션 타이틀"
    }

6. 각 row 클릭 시 발생하는 이벤트: didSelectRowAt

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("셀 선택~")
    }

7. 셀 편집 상태 설정: editingStyle

  • 스와이프 했을 때 삭제할 수 있도록 설정해주는 코드
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if indexPath.section == 1 {
            if editingStyle == .delete {
                list.remove(at: indexPath.row)
                tableView.reloadData()
            }
        }
    }

8. 셀 스와이프 ON/OFF 여부 설정: canEditRowAt

  • 섹션별로 스와이프 가능 여부 설정해주는 코드
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return indexPath.section == 0 ? false : true
    }

IndexPaths

특정 섹션의 특정 행에 대한 위치 정보(좌표 정보)
섹션과 행의 속성을 통해 엑세스 가능
indexPath.row / indexPath.section

기타

  • outlet 연결하지않아도 테이블뷰 가져올 수 있다!
    ➡️ UIViewController의 view는 연결하지 않아도 view. 이렇게 사용할 수 있었던것처럼
    tableViewController에서도 애플이 미리 view라는 이름으로 table view가 연결이 돼있음

📂 TableViewCell Reuse mechanism

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "memoCell") else {
            return UITableViewCell()
        }
  • TableViewCell의 ReuseIdentifier: cell이 재활용될 때 표시하기 위해 사용하는 문자열, 재사용할 객체를 나타내는 문자열. 반드시 nil이면 안된다

Table 자체의 cell이 많아지는 경우, 당장 유저에게 보여지는 cell보다 필요한 cell의 갯수가 많은 경우가 대다수이다. 이때 모든 cell을 미리 준비해놓는 것이 아니라 화면에 보여지는 셀들만큼만 준비를 해놓고 유저가 화면을 스크롤하는 경우 이들을 재활용해서 사용하게 된다.

📂 기타

오토레이아웃 시 Constrain to Marigns

헤더, 셀의 배치를 하는 경우 점선이 위치하는 경우가 생김, 약간의 여백 → 애플이 준수하라고 하는 가이드, 최소한의 여백 이정도는 남겨라~

tableView.reloadData()

배열에 추가 → 테이블뷰에 업데이트 시키기 위해서 tableView.reloadData() (왜냐하면 테이블뷰는 뷰가 로드될때 한 번 다 디자인돼서 가만히 있기 때문) 갱신해주세요~ 요청하는 것

👩‍💻 추가 스터디

📂 Optional Binding

if let

var height: Int? = 160
if let myHeight = height {
	print("My height is \(myHeight)")
} else {
	print("I don't know")
}

guard

var height: Int? = 160
guard let myHeight = height else {print("I don't know")}

📂 Optional Chaining

  • 하위 프로퍼티에 옵셔널값이 있는지 연속적으로 확인하다가 nil이 발견되면 nil이 반환되는 형식
let cell = tableView.dequeueReusableCell(withIdentifier: "memoCell")
        
if indexPath.section == 0 {
	cell?.textLabel?.text = "첫번째 섹션입니다 - \(indexPath)"
} 

이때 cell과 textLabel 모두 옵셔널 타입이므로 옵셔널 체이닝으로 값을 받아오고 있다.

guard let cell = tableView.dequeueReusableCell(withIdentifier: "memoCell") else {
            return UITableViewCell()
        }
        
 if indexPath.section == 0 {
	cell.textLabel?.text = "첫번째 섹션입니다 - \(indexPath)"
} 

위와 동일한 코드지만 guard문을 사용하여 조금 더 안전하게 cell을 사용할 수 있다.

0개의 댓글