Refactoring (리펙토링)
[iOS - swift] DataSource 리펙토링 - Section과 Item을 enum으로 놓고 dictionary로 관리하기
jake-kim
2024. 1. 26. 01:38
일반적인 DataSource 관리
- Section이 여러개이고 Item도 여러개인 경우, 보통 dataSource를 2차원 배열로 하거나, Section과 Item을 갖는 struct를 만들어서 관리
class ViewController: UIViewController {
struct Section {
var title: String
var items: [String]
}
var sections: [Section] = [
Section(title: "header is a", items: ["A1", "A2"]),
Section(title: "header is b", items: ["B1", "B2"]),
]
let tableView: UITableView = {...}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
sections.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
sections[section].title
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
sections[section].items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = sections[indexPath.section].items[indexPath.row]
return cell
}
}

- 이렇게 관리하면 Section이 하나 늘어나거나 Item의 유형이 늘어나는 경우, 타입을 명확히해야 관리에 용이한데 위코드는 Section, Item모두 enum으로 되어 있지 않고 단순히 index로만 접근해야하므로 관리가 어려운 코드
- struct를 가지고 Section하나와 [Item]을 프로퍼티로 지정해놓고 wrapping해서 사용해도 되지만 이보더 더 직관적이고 별도의 struct없이 관리할 수 있는 방법은 dictionary를 활용한 방법
Section과 Item을 enum으로 놓고 dictionary로 관리하기
- Section과 Item을 enum으로 선언
enum Section: Int, CaseIterable {
case a
case b
var headerTitle: String {
switch self {
case .a:
"header is a"
case .b:
"header is b"
}
}
}
enum Item: String {
case A1
case A2
case B1
case B2
}
- dataSource를 dictionary로 선언
- key값은 Section으로하고 value값은 Item배열로 선언
- dictionary로 관리하면 더욱 직관적으로 어떤 section에 어떤 Item이 있는지 쉽게 파악이 가능
var dataSource: [Section: [Item]] = [
.a: [.A1, .A2],
.b: [.B1, .B2],
]
- dataSource 부분도 아래처럼 Section enum을 활용하여 처리
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
dataSource.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
items(section: section).count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
Section(rawValue: section)?.headerTitle
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let items = items(section: indexPath.section)
let item = items[indexPath.item]
cell.textLabel?.text = item.rawValue
return cell
}
private func items(section index: Int) -> [Item] {
dataSource[Section(rawValue: index) ?? .a] ?? []
}
}