배열의 끝에 새 값을 넣을 때 사용함
var numbers = [1, 2, 3]
numbers.append(4)
print(numbers) // [1, 2, 3, 4]
👉 [1, 2, 3] 뒤에 4를 붙인 것
배열 안에서 내가 정한 자리에 값을 넣을 수 있음
var numbers = [1, 2, 4]
numbers.insert(3, at: 2)
print(numbers) // [1, 2, 3, 4]
👉 2번째 자리에 3을 끼워 넣은 것 (자리는 0부터 시작)
배열에 여러 값을 한 번에 더하고 싶을 때 사용함
var numbers = [1, 2, 3]
numbers += [4, 5]
print(numbers) // [1, 2, 3, 4, 5]
👉 4와 5를 한 번에 추가
var numbers = [1, 2, 3, 4]
numbers.remove(at: 2)
print(numbers) // [1, 2, 4]
👉 2번째 자리에 있던 3이 없어짐
배열의 맨 앞이나 맨 뒤 값을 지우고 싶을 때 씀
var numbers = [1, 2, 3, 4]
numbers.removeFirst()
print(numbers) // [2, 3, 4]
numbers.removeLast()
print(numbers) // [2, 3]
👉 처음 값(1)과 마지막 값(4)이 지워짐
배열 안에 있는 걸 전부 지워버리고 싶을 때 사용
var numbers = [1, 2, 3, 4]
numbers.removeAll()
print(numbers) // []
👉 다 없어져서 빈 배열이 됨
배열에서 내가 원하는 조건에 맞는 값만 뽑아내는 것
let numbers = [1, 2, 3, 4, 5, 6]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers) // [2, 4, 6]
👉 짝수만 골라낸 것 ($0은 배열 안의 하나하나를 뜻함)
배열 안의 숫자나 값을 순서대로 정리하는 방법
크기 순으로 정리하거나 거꾸로 정리할 수 있음
배열을 정렬하지만, 원래 배열은 그대로 두고 새로운 정렬된 배열을 만들어 줌
let numbers = [3, 1, 4, 1, 5, 9]
let sortedNumbers = numbers.sorted()
print(sortedNumbers) // [1, 1, 3, 4, 5, 9]
👉 [3, 1, 4, 1, 5, 9]을 오름차순으로 정렬해서 [1, 1, 3, 4, 5, 9]이라는 새 배열로 만듦
원래 배열은 그대로 있음
배열을 정렬하고, 그 결과를 원래 배열에 저장함
var numbers = [3, 1, 4, 1, 5, 9]
numbers.sort()
print(numbers) // [1, 1, 3, 4, 5, 9]
👉 정렬된 결과가 numbers에 바로 저장됨
sorted(by: >) 또는 sort(by: >)를 쓰면 큰 수부터 정렬됨
let numbers = [3, 1, 4, 1, 5, 9]
let descendingNumbers = numbers.sorted(by: >)
print(descendingNumbers) // [9, 5, 4, 3, 1, 1]
👉 숫자가 큰 것부터 차례로 정렬함
| 할 일 | 쓰는 방법 |
|---|---|
| 맨 끝에 추가 | append() |
| 중간에 추가 | insert() |
| 여러 개 추가 | += |
| 앞/뒤 값 삭제 | remove(at:) |
| 특정 값 삭제 | removeFirst(), removeLast() |
| 전부 삭제 | removeAll() |
| 조건에 맞는 값만 골라내기 | filter() |
| 오름차순 정렬 | sorted(), sort() |
| 내림차순 정렬 | sorted(by: >), sort(by: >) |
| 할 일 | 쓰는 방법 |
|---|---|
| 딕셔너리 생성 | var dict: [String: Int] = ["A": 1, "B": 2] |
| 값 가져오기 | dict["A"] → Optional(1) |
| 기본값 설정 | dict["C", default: 0] → 0 |
| 할 일 | 쓰는 방법 |
|---|---|
| 새 값 추가 | dict["C"] = 3 |
| 기존 값 수정 | dict["A"] = 10 |
| 기존 값 반환하며 수정 | dict.updateValue(20, forKey: "B") → 이전 값 반환 |
| 할 일 | 쓰는 방법 |
|---|---|
| 특정 키 삭제 | dict.removeValue(forKey: "A") |
| nil로 삭제 | dict["B"] = nil |
| 전부 삭제 | dict.removeAll() |
| 할 일 | 쓰는 방법 |
|---|---|
| 키-값 모두 순회 | for (k, v) in dict {} |
| 키만 순회 | for k in dict.keys {} |
| 값만 순회 | for v in dict.values {} |
| 할 일 | 쓰는 방법 |
|---|---|
| 조건에 맞는 값만 남기기 | dict.filter { $0.value > 90 } |
| 값을 문자열로 변환 | dict.map { "($0.key): ($0.value)" } |
데이터 모델링은 데이터를 구조화하고, 데이터 간 관계(Entity, Attribute, Relationship)를 정의하는 작업
struct User {
let id: Int
var name: String
var email: String
}
값 타입이라 복사되어 전달됨
주로 간단하고 변하지 않는 데이터에 적합
mutating func updateEmail(newEmail: String) {
self.email = newEmail
}
mutating 키워드로 구조체 내부 속성 변경 가능
struct Product {
let id: Int
var name: String
var price: Double
mutating func applyDiscount(_ percentage: Double) {
price -= price * (percentage / 100)
}
}
Model : 데이터, 비즈니스 로직 담당 (Struct, API 등)
View : 사용자에게 보여지는 화면 (UILabel, UIView 등)
Controller : Model과 View 연결, 사용자 입력 처리 (UIViewController)
// Model
struct User { let id: Int; var name: String; var email: String }
// View
class UserView: UIView {
func updateUI(user: User) { /* 사용자 정보 표시 */ }
}
// Controller
class UserViewController: UIViewController {
var user = User(...)
func updateUserEmail(newEmail: String) { /* 모델 업데이트 및 뷰 반영 */ }
}
데이터 저장 : 사용자, 상품, 게시글 등
데이터 처리 : 가공, 로직 적용
변경 감지 : 값이 바뀌면 UI에 반영
외부 통신 : API, DB와 연결
struct User {
let id: Int
var name: String
var email: String
}
사용자의 정보를 저장하는 구조체
데이터만을 책임짐
UIKit 기반 View
import UIKit
class UserView: UIView {
let nameLabel = UILabel()
let emailLabel = UILabel()
func updateUI(user: User) {
nameLabel.text = "이름: \(user.name)"
emailLabel.text = "이메일: \(user.email)"
}
}
UI 요소 정의
사용자에게 데이터 시각적으로 보여줌
사용자 입력 X, 로직 없음
콘솔 기반 View (간단 예제)
class UserView {
func displayUserInfo(_ user: User?) {
guard let user = user else {
print("사용자를 찾을 수 없습니다.")
return
}
print("사용자 정보: \(user.name) (\(user.email))")
}
}
UIKit 기반 Controller
import UIKit
class UserViewController: UIViewController {
var user = User(id: 1, name: "Alice", email: "alice@example.com")
let userView = UserView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(userView)
userView.updateUI(user: user)
}
func updateUserEmail(newEmail: String) {
user.email = newEmail
userView.updateUI(user: user)
}
}
콘솔 기반 Controller (간단 예제)
class UserController {
let userManager = UserManager()
let userView = UserView()
func addUser(id: Int, name: String, email: String) {
let user = User(id: id, name: name, email: email)
userManager.addUser(user)
}
func showUserInfo(id: Int) {
let user = userManager.findUser(byID: id)
userView.displayUserInfo(user)
}
}
class UserManager {
private var users: [User] = []
func addUser(_ user: User) {
users.append(user)
}
func findUser(byID id: Int) -> User? {
return users.first { $0.id == id }
}
func listUsers() {
for user in users {
print("ID: \(user.id), 이름: \(user.name), 이메일: \(user.email)")
}
}
}
복수의 사용자 관리 (배열로 저장)
Model이지만 로직 포함됨 (데이터 가공 및 검색)
let userController = UserController()
userController.addUser(id: 1, name: "Alice", email: "alice@example.com")
userController.addUser(id: 2, name: "Bob", email: "bob@example.com")
userController.showUserInfo(id: 1) // 사용자 정보: Alice (alice@example.com)
userController.showUserInfo(id: 3) // 사용자를 찾을 수 없습니다.
| 이점 | 설명 |
|---|---|
| 코드 분리 | 역할별로 책임을 나눠 유지보수가 쉬움 |
| 확장성 | 각 구성요소를 독립적으로 수정 가능 |
| 재사용성 | View나 Model 재활용 가능 |
표 형태의 목록을 표시하는 UI 구성 요소
TableView: 전체 목록 컨테이너
Section: 데이터를 그룹화한 단위 (0개 이상 가능)
Row (행): 각 섹션의 개별 항목
Cell: 실제로 사용자에게 보여지는 각 행의 뷰
| 구성 요소 | 역할 |
|---|---|
| UITableViewCell | 각 행을 구성하는 셀 (기본 스타일 or 커스텀 가능) |
| UITableViewDataSource | 데이터를 제공하고 셀을 생성하는 프로토콜 |
| UITableViewDelegate | 셀 선택, 높이 조절 등 사용자 상호작용 처리 |
테이블 뷰 전용 컨트롤러.
뷰에 직접 테이블 뷰를 추가하지 않아도 됨
데이터 연결, 셀 생성, 선택 처리 등이 기본 내장됨
정적인 목록
class FruitListViewController: UITableViewController {
let fruits = ["사과", "바나나", "딸기", "오렌지", "포도"]
override func viewDidLoad() {
super.viewDidLoad()
self.title = "과일 목록"
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = fruits[indexPath.row]
return cell
}
}
동적인 목록 (배열 활용)
class DynamicListViewController: UITableViewController {
var items = ["아이템 1", "아이템 2", "아이템 3"]
override func viewDidLoad() {
super.viewDidLoad()
self.title = "동적 목록"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "추가", style: .plain, target: self, action: #selector(addItem))
}
@objc func addItem() {
let newItem = "아이템 \(items.count + 1)"
items.append(newItem)
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = items[indexPath.row]
return cell
}
}
| 메서드 | 설명 |
|---|---|
| numberOfRowsInSection | 각 섹션의 셀 개수 반환 |
| cellForRowAt | 각 셀에 들어갈 데이터 지정 |
| dequeueReusableCell | 셀 재사용으로 성능 최적화 |
| reloadData() | 데이터 변경 후 화면 갱신 요청 |
1️⃣ 유지 보수가 쉬움: 데이터만 바꾸면 됨
2️⃣ 유연성: 정렬, 필터링 간단
3️⃣ 동적 처리 용이: 네트워크, 사용자 입력 반영 쉬움
.default, .subtitle, .value1, .value2 형태로 간단한 정보를 빠르게 표현 가능
간단하지만 디자인 제한이 있음
적은 개발 시간, 코드 한 줄로 구현 가능
UITableViewCell을 상속받아 UILabel, UIImageView 등 자유롭게 구성
복잡한 UI 필요할 때 필수
오토레이아웃과 translatesAutoresizingMaskIntoConstraints = false 설정이 중요
재사용 식별자(reuseIdentifier) 꼭 사용
배열 items에 데이터를 추가하거나 삭제
tableView.insertRows, deleteRows, reloadRows, reloadData() 등으로 UI 동기화
직접 배열을 바꾸고, 그 변화에 맞게 테이블을 업데이트해줘야 함
커스텀 셀 내부에 버튼이 있는 경우,
이벤트를 처리할 수 있도록 델리게이트 패턴이나 클로저를 활용하는 방식도 자주 사용됨
var onButtonTap: (() -> Void)?
@objc func buttonTapped() {
onButtonTap?()
}
XIB로 만들면 시각적으로 디자인 가능
코드보다 직관적이지만, 코드 재사용성이 떨어질 수 있음
커스텀 셀의 높이가 내용에 따라 달라지는 경우에는 다음 설정을 추가함
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 60
reloadData()는 테이블 뷰 전체를 다시 로드하고 UI를 최신 데이터로 갱신함
데이터 배열이 변경된 후
서버 응답 등 외부 데이터 수신 후
필터링, 정렬, 전체 갱신이 필요할 때
여러 셀을 한꺼번에 업데이트해야 할 때
items.append("새 항목")
tableView.reloadData()
numberOfSections, numberOfRowsInSection 메서드 다시 호출
각 셀에 대해 cellForRowAt 호출
전체 테이블 뷰 화면 새로 그림
전체 UI를 간단하고 직관적으로 갱신 가능
모든 셀을 다시 그려서 성능 저하 가능
스크롤 위치와 애니메이션 초기화
한 셀만 바뀌어도 전체가 다시 로드됨
| 상황 | 메서드 |
|---|---|
| 행 추가 | insertRows(at:with:) |
| 행 삭제 | deleteRows(at:with:) |
| 특정 행 갱신 | reloadRows(at:with:) |
let indexPath = IndexPath(row: 2, section: 0)
tableView.reloadRows(at: [indexPath], with: .automatic)
데이터 배열을 먼저 변경한 뒤 reloadData()를 호출해야 함
그렇지 않으면 배열과 셀 내용이 불일치할 수 있음
자주 반복 호출하면 퍼포먼스 저하 발생 가능
| 상황 | 권장 방법 |
|---|---|
| 전체 데이터를 새로 불러올 때 | reloadData() |
| 일부 항목만 바뀌었을 때 | reloadRows, insertRows, deleteRows |
| 성능이 중요한 대형 목록일 때 | 부분 갱신 또는 diff 방식 고려 |
생각보다 어려운 게 많았던 3-1 ~ 3-2..
내일 한 번 더 복습해야할 듯..!ㅜㅜ