메모앱 만들기 심화 프로젝트를 진행하기에 앞서, 테이블뷰의 섹션을 생성하고 각 섹션마다 헤더와 푸터를 설정하는 방법에 대해 알아보자
간단한 예제 코드는 아래와 같다.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// 더미 데이터
let data = [
["Apple", "Banana", "Cherry"],
["one", "two", "three"],
["1", "2", "3"]
]
override func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView(frame: view.bounds, style: .grouped)
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
// 테이블뷰에 헤더와 푸터 등록
tableView.register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "header")
tableView.register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "footer")
}
// 섹션 수 반환
func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
// 각 섹션의 셀 수 반환
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].count
}
// 셀 생성 및 데이터 삽입
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = data[indexPath.section][indexPath.row]
return cell
}
// 섹션 헤더 뷰 설정
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "header")!
headerView.textLabel?.text = "Section \(섹션 + 1) Header"
return headerView
}
// 섹션 푸터 뷰 설정
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "footer")!
footerView.textLabel?.text = "Section \(섹션 + 1) Footer"
return footerView
}
}
해당 예제를 토대로 내 프로젝트에 적용해봤는데 문제가 발생했다.
문제1. 테이블뷰의 섹션 및 헤더 Height 값을 지정했으나 시뮬레이터에 나오지 않음
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10.0
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
문제2. 섹션으로 나누고 난 후 메모 스위치 작동 시 업데이트 안됨
// 처음 고민
let category = ["일반", "반려동물", "집", "과제", "운동"]`
override func numberOfSections(in tableView: UITableView) -> Int {
return category.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 카테고리 배열의 값과 memoList의 카테고리 값이 매칭되면 해당 memoList의 카운트를 반환
for index in 0..<category.count {
if category[index] == myMemo.memoList[index].category {
// 실행할 코드
}
return myMemo.memoList[section].count
}
}
일단 기존 데이터 구조를 살려 배열로 memoList를 유지하는 방법으로 진행했다.
문제3. memoList에 있는 카테고리를 Set을 통해 집합을 만들었으나 실행하니 순서가 뒤죽박죽이 됨
문제4. 디테일페이지로 들어가면 섹션의 셀의 내용이 처음 추가한 셀의 내용과 동일하게 나옴
@IBAction func memoSwitch(_ sender: UISwitch) {
guard let tableView = superview as? UITableView,
let indexPath = tableView.indexPath(for: self) else {
return
}
let categories = Array(Set(MemoManager.shared.memoList.map { $0.category ?? "일반" })).sorted()
let category = categories[indexPath.section]
let memoListInSection = MemoManager.shared.memoList.filter { $0.category == category }
var memo = memoListInSection[indexPath.row]
memo.isCompleted = sender.isOn
updateLabelStrikeThrough()
MemoManager.shared.updateMemo(at: indexPath.row, newContent: memo.content, isCompleted: memo.isCompleted, insertDate: memo.insertDate, targetDate: memo.targetDate, priority: memo.priority, category: memo.category, progress: memo.progress)
// 로그 출력 (Memo 객체의 내용 출력)
for memo in MemoManager.shared.memoList { print(memo) }
}
자 이제.. 그러다가 문득 필터함수에 대해 의문을 가지게 되었다.(그러지 말았어야..)
메모를 추가하고 수정하고 로드할 때마다 계속 필터로 카테고리를 찾아야 하니 메모리가 많이 사용되지 않을까 하며..
고민. filter 함수쓰면 매번 필터링을 돌아야해서 메모리를 많이 쓰지 않을까?
문제5. 딕셔너리로 데이터 구조를 변경하였으나, 입력값을 인식 못해 메모가 추가되지 않음
문제6. 카테고리는 만들어지는데 메모가 수정이 안됨
if newMemoList[category] == nil {
newMemoList[category] = [] // 해당 카테고리의 배열이 없다면 생성
}
결국 몇시간 부여잡고 딕셔너리 포기하고 filter로 돌아옴...
지금 필터도 셀 재사용 때문에 완벽하게 구현하지는 못했는데 이거 해결하고 나면 딕셔너리 뽀개준다.. 기다리셈..