iOS/UIKIT

UITableView를 UIView 넣어야 하나? 아니면 UIViewController에 넣어야 하나?

밤새는 탐험가89 2024. 8. 16. 22:47

UITableView를 UIView에 넣는 것과 UIViewController에 직접 넣는 것 사이에는 몇 가지 중요한 차이점이 있습니다.

 

1. UIView 내부에 UITableView를 넣는 경우

  • DetailContentView 재사용 가능성: 만약 DetailContentView를 다른 뷰 컨트롤러에서도 재사용할 가능성이 있다면, UITableView를 DetailContentView 안에 넣어도 좋습니다. 이렇게 하면 이 뷰를 포함한 모든 컨트롤러가 UITableView를 공통적으로 사용하게 됩니다.
  • 뷰 계층 구조의 복잡도 감소: UITableView와 다른 UI 요소들을 하나의 UIView 서브클래스로 묶으면, 뷰 계층 구조가 더 간단해지고, 레이아웃과 관리가 쉬워질 수 있습니다.
  • UITableViewDelegate와 UITableViewDataSource의 구현: UIView 안에 UITableView를 포함시키면, 이 뷰는 그 자체로는 UITableViewDelegate나 UITableViewDataSource를 구현하지 않기 때문에, 이를 사용하려는 UIViewController가 해당 프로토콜을 준수해야 합니다. 또는 DetailContentView 자체가 해당 프로토콜을 준수하도록 설정할 수도 있습니다.

그러나, UIView는 기본적으로 UIViewController보다 훨씬 가벼운 구조체입니다. 네트워크 호출이나 뷰 컨트롤러 수준에서 처리해야 하는 복잡한 로직을 UIView에 직접 넣는 것은 권장되지 않습니다.

 

2. UIViewController 내부에 UITableView를 넣는 경우

  • 데이터 및 로직 관리: UITableView를 UIViewController에 직접 넣으면, 해당 뷰 컨트롤러가 자연스럽게 모든 관련 데이터 소스, 델리게이트 메서드, 그리고 네트워크 호출 등을 처리할 수 있습니다. UIViewController는 이런 복잡한 로직을 처리하는 데 적합한 위치입니다.
  • 유지보수와 확장성: 대부분의 경우, UITableView와 관련된 로직은 UIViewController 내부에 있는 것이 좋습니다. 이는 뷰 컨트롤러가 뷰와 관련된 데이터 로직을 처리하는 주체이기 때문입니다.
  • 의존성 문제: 만약 UITableView를 UIView에 넣게 되면, 뷰 컨트롤러가 뷰와 너무 밀접하게 연결될 수 있습니다. 예를 들어, 뷰 내부에서 데이터 소스를 처리하게 되면, 뷰가 특정 컨트롤러와만 작동하도록 강하게 결합될 수 있습니다.

 

추천

UITableView를 DetailContentView에 UI 요소로서 포함시키되, delegate와 dataSource 같은 로직은 UIViewController에서 구현하는 것을 추천합니다. 이렇게 하면 뷰와 컨트롤러 간의 책임이 명확히 분리되어, 코드의 유지보수성과 확장성을 높일 수 있습니다.

 

이렇게 분리하는 이유는 다음과 같습니다:

  1. UIView의 역할: DetailContentView는 UI를 구성하는 뷰로서, UITableView와 같은 UI 요소들을 포함하는 역할을 담당합니다. 하지만 DetailContentView 자체는 데이터나 로직을 처리하는 책임을 갖지 않습니다.
  2. UIViewController의 역할: UIViewController는 뷰와 관련된 데이터 관리, 사용자 입력 처리, 네트워크 호출 등 로직을 처리하는 역할을 합니다. 따라서, UITableView의 delegate 및 dataSource를 관리하고, 데이터 소스와 같은 비즈니스 로직을 구현하기에 적합합니다.
  3. 유지보수성과 확장성: 이 구조에서는 DetailContentView가 UITableView와 관련된 UI를 표시하는 데만 집중하므로, 다른 뷰 컨트롤러에서도 DetailContentView를 쉽게 재사용할 수 있습니다. 동시에, UIViewController에서 UITableView의 데이터 처리 로직을 독립적으로 관리할 수 있어, 코드 수정이 더 쉬워집니다.

 

 

예시 코드 

1. DetailContentView에 UITableView 추가

class DetailContentView: UIView {
    
    let tableView: UITableView = {
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        addSubview(tableView)
        configureConstraints()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func configureConstraints() {
        NSLayoutConstraint.activate([
            tableView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            tableView.topAnchor.constraint(equalTo: self.topAnchor),
            tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        ])
    }
}

 

 

2. DetailViewController에서 delegate와 dataSource 설정

class DetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    private let detailContentView = DetailContentView()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(detailContentView)
        detailContentView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            detailContentView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            detailContentView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            detailContentView.topAnchor.constraint(equalTo: view.topAnchor),
            detailContentView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        detailContentView.tableView.delegate = self
        detailContentView.tableView.dataSource = self
        
        // 필요한 데이터 로드 및 UI 업데이트
    }

    // UITableViewDataSource 메서드들
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10 // 예시 데이터 수
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = "Row \(indexPath.row)"
        return cell
    }

    // UITableViewDelegate 메서드들 (필요시)
}

 

 

⭐️ UITableView의 register 메서드 호출은 어디서 하나?

 

UITableView에 register 메서드를 호출하여 셀을 등록하는 작업은 일반적으로 UIViewController에서 처리하는 것이 좋습니다.

register 작업은 UITableView의 설정과 관련이 있으며, 데이터 처리나 로직과 밀접한 관련이 있기 때문입니다.

 

이유:

  • 컨트롤러의 책임: UIViewController는 뷰와 데이터 간의 상호작용을 관리하는 역할을 합니다. 셀의 등록은 UITableView의 데이터 소스와 뷰 간의 관계를 설정하는 작업이므로, UIViewController에서 처리하는 것이 역할 분리에 적합합니다.
  • 확장성: 셀을 어떻게 등록하고 사용하는지에 대한 로직이 UIViewController에 있으면, 나중에 셀을 교체하거나 새로운 셀을 추가할 때 더 쉽게 관리할 수 있습니다.

 

예시 코드

UITableView의 셀을 register하는 코드를 UIViewController에서 구현하는 방법은 다음과 같습니다.

class DetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    private let detailContentView = DetailContentView()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(detailContentView)
        detailContentView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            detailContentView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            detailContentView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            detailContentView.topAnchor.constraint(equalTo: view.topAnchor),
            detailContentView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        // UITableView 셀 등록
        detailContentView.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        detailContentView.tableView.delegate = self
        detailContentView.tableView.dataSource = self
        
        // 필요한 데이터 로드 및 UI 업데이트
    }

    // UITableViewDataSource 메서드들
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10 // 예시 데이터 수
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = "Row \(indexPath.row)"
        return cell
    }

    // UITableViewDelegate 메서드들 (필요시)
}

 

 

왜 register는 UIViewController에서 처리해야 하나?

  1. 유연성: UIViewController에서 셀을 등록하면 다양한 셀 타입을 쉽게 추가하거나 변경할 수 있습니다.
  2. 구성의 일관성: delegate와 dataSource를 설정하는 것과 같은 맥락에서, 셀 등록 작업도 UIViewController에서 처리하면 뷰와 로직이 명확하게 구분됩니다.
  3. 명확한 책임 분리: UIView는 순수하게 UI만 담당하고, 모든 로직 관련 작업은 UIViewController에서 처리하는 것이 유지보수에 유리합니다.

따라서, 셀 등록(register) 작업은 UIViewController에서 하는 것이 더 바람직합니다.