관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] DataSource 리펙토링 - Section과 Item을 enum으로 놓고 dictionary로 관리하기 본문

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] ?? []
    }
}

 

* 전체 코드: https://github.com/JK0369/ExDataSource

Comments