TIL 7일차 - To-do 클론 앱 따라하기 (1회 차)

(1회 차) 구현 목표
- 스토리보드로 리스트 UI 구성하기
- 배열에 담긴 더미(가짜) 데이터를 UITableView에 표시하기
- UITableView를 활용하여 화면 구현하기
(1회 차) 완성될 화면
- 상단에 제목 "할 일 목록" 표시
- 중단에 UITableView를 사용해할 일 목록 표시
- 하단에 기능이 아직 연결되지 않은 "새 할 일 추가" 버튼 배치
1. to Xcode 'TodoApp' 프로젝트 만들기

2. Main.storyboard에서 UI 구성하기
1) 상단에 Label 추가
스토리보드 키고 command+shift+L 눌러서 레이블창 띄우고 Label을 ViewController의 상단에 배치함
그리고 텍스트를 "할 일 목록"으로 입력하고 System, Bold, 24pt로 설정하고 중앙정렬한다.

2) AutoLayout설정하기


3) UITableView 추가하기
1. 아까와 마찬가지 방식으로 Table View를 Label 아래에 불러온다.
2. 제약조건을 설정한다.
Background color를 시스템 그린 컬러로 설정하여 눈에 잘 들어오게 설정함
Top: Label로 부터 20pt
Leading/Trailing: superview로부터 0pt
Bottom은 75pt 떨어지게 설정함


4) TableView Cell을 불러와 넣고 Identifier를 "TodoCell"로 설정하기

5) 버튼 추가
1. 화면 하단에 UIButton "새 할 일 추가" 버튼 추가하기
2. Bottom은 safe area로부터 45pt만큼 떨어지고, CenterX: 수평중앙정렬 시킴
3.ViewController.swift에 연결하기

1) @IBoutlet 연결
ctrl누르고 Table View를 꾹 눌러서 ViewController 바로 밑에 집어넣기 (Name은 tableView로)
(코드옆에 동그란버튼 가리켰을 때 storyboard위의 Table View에 표시가 되면 정상적으로 연결된 것임.)
2) 이 ViewController가 테이블뷰의 대리인(대표자) 역할을 하겠다”라는 선언 해주기

UITableView는 그릇일 뿐으로 테이블 뷰 스스로는 몇 칸이 있는지, 각 칸에 무엇을 넣을지, 셀을 눌렀을 때 어떤 동작을 할 것인지 결정할 수 없다. 그래서 대신 결정해 주는 애들이 위에서 추가한 delegate와 dataSource이다.
먼저 UITableViewDataSource(데이터 담당)은 '무엇을 보여줄까?' 하는 역할을 하고
얘가 반드시 구현해야 하는 질문에는 두 개가 있는데
tableView(_:numberOfRowsInSection:) // 몇줄임?
tableView(:_cellForRowAt:) // 이 줄에는 뭘 보여줄까?
다음으로 UITableViewDelegate (행동 담당)으로 '사용자가 뭘 했을 때 어떤 반응을 할까?' 하는 역할을 한다.
예를 들어,
tableView(:_didSelectRowAt:) //셀을 눌렀을 때 뭘 할까?

viewDidLoad 함수 밑으로 위에서 삽입된 두 개의 함수 붙여 넣기 하기

짜잔~ 완성! 하고 빌드를 했다.!! 끝!인 줄 알았는데

하지만 내 예상과는 다르게 내가 만들어놓은 셀들의 속눈썹도 안 보인다.. 왜 안보일까? 심지어 에러도 안 나고 빌드는 또 잘만 됨.;;

ViewDidLoad() 함수 안에 이 두 문장을 추가해 보자
왜 해야 하나? 첫 문장부터 해석해 보자면 tableView가 묻는다. 내 dataSource는 누가 넣어주게? 바로 self가 넣어줘! 그 self는 무엇이냐?
위에서 말했듯 대표자인 ViewController를 말하는 거다.
delegate도 마찬가지이다.
얘네를 넣고 나면 정상적으로 빌드된다. 얘네를 빼먹으면 진짜 큰일 나니까 무조건 해야 함!

근데 뭔가 심심하다 그래서 추가한 함수
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// animated가 false면 즉시 사라짐
}
// didSelectRowAt: 사용자가 이 줄을 눌렀음을 알려주는 알림 함수임
버튼을 누르면 선택표시(회색)가 부드럽게 사라진다.
이제 셀에 todoApp의 취지에 맞게 '해야 할 일'들을 집어넣을 건데 일단 배열을 만들어 더미데이터를 만들어 주었다.
let todos = ["Swift 문법 공부하기", "운동 하기", "듀오링고 하기"]
그리고 numberOfRowsInsection의 return값도 배열의 원소의 수만큼 정해지도록 동적으로 바꿔준다.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return todos.count // 배열의 원소의 수만큼 return함
}
그리고 문자열 "JH" 대신 아까 만들었던 배열을 집어넣어줄 것인데
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TodoCell", for: indexPath)
cell.textLabel?.text = todos[indexPath.row] //todos 배열의 원소 불러오기
return cell
}
근데 여기에서 궁금했던 게 왜 indexPath.row인지 모르겠는 거다..
일단! indexPath가 뭔지부터 정확히 잡자
IndexPath는 위치 정보 묶음이다.
즉:
- section = 몇 번째 묶음
- row = 그 묶음 안에서 몇 번째 줄로
Int값 index와 헷갈리면 절대 안 된다..
참고로 테이블뷰는 구조가 이렇게 생김
지금 내 코드는:
- section = 1개
- todos 배열 = 한 섹션의 데이터
그래서 항상:

'iOS > UIkit ' 카테고리의 다른 글
| [iOS-UIKit] 스토리보드 -> 코드베이스 환경설정하는 방법 (0) | 2026.01.22 |
|---|---|
| [iOS] KPT 회고 (왜_되는지_모름 팀) (0) | 2026.01.05 |
| [iOS] 팀 프로젝트 첫 코드 리뷰 (타입 안정성 개선) (1) | 2026.01.02 |
| [iOS] 팀 소개 앱 프로젝트 개인 페이지 제작기 (0) | 2025.12.30 |
| [iOS] 팀 소개 어플리케이션 프로젝트 (0) | 2025.12.29 |