iOS

웹개발자의 iOS 개발기(10) - [UIKit] 테이블뷰, TableView

whh__ 2025. 1. 26. 23:16

테이블뷰에 대하여 공부해 보았습니다.

UIKit은 Delegate 패턴으로 UI요소를 컨트롤하여서 해당 패턴이 익숙해질 때까지 많이 연습이 필요해 보입니다.

01. 테이블뷰로 화면 그리기

MyTableViewController.swift

테이블뷰 그려보기

  • TableView 생성, 그 안에 TableViewCell 생성

Table View

 

  • Table View Cell 식별자 정의

Table View Cell Identifier 정의

  • 코드 작성
import UIKit

class MyTableViewController: UIViewController {

    
    @IBOutlet weak var myTableView: UITableView!
    let cellData = ["Hello TableView!", "Hello Swift!", "Hello UIKit!"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .brown
        myTableView.backgroundColor =
            .green
        myTableView.delegate = self
        myTableView.dataSource = self
    }
}

extension MyTableViewController: UITableViewDelegate, UITableViewDataSource{
    
    // cell 개수 return, return한 만큼 for문 돌면서 화면에 그리기 때문에 실제 개수와 다르면 에러
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellData.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
        cell.textLabel?.text = cellData[indexPath.row]
        return cell
    }
    
}

 

Table View

02. Delegate 친해지기

Delegate

  • 위임자
  • 대리자

TableView의 UITableViewDelegate, UITableViewDataSource를 상속받아 함수를 구현하면

Delegate 패턴으로 개발자가 호출하는 게 아닌 TableView가 내부적으로 호출해서 사용한다.

DelegateTestController.swift

import UIKit

protocol AdminDelegate {
    func doTask()
}

class DelegateTestController: UIViewController {

    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var helloLabel: UILabel!
    var admin: Admin?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        admin = Admin(delegate: self)
    }
    
    @IBAction func didTabButton(_ sender: Any) {
        if let name = nameTextField.text {
            helloLabel.text = "Hello \\(name)!"
        }
        admin?.delegate.doTask()
    }
    
}

extension DelegateTestController: AdminDelegate {
    func doTask() {
        print("저 지금 일 잘하고 있습니다!")
    }
}

struct Admin {
    var delegate: AdminDelegate
}

MyTableViewController.swift

import UIKit

class MyTableViewController: UIViewController {

    
    @IBOutlet weak var myTableView: UITableView!
    let cellData = ["Hello TableView!", "Hello Swift!", "Hello UIKit!"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .brown
        myTableView.backgroundColor =
            .green
        myTableView.delegate = self
        myTableView.dataSource = self
    }
}

extension MyTableViewController: UITableViewDelegate, UITableViewDataSource{
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }
    
    // cell 개수 return, return한 만큼 for문 돌면서 화면에 그리기 때문에 실제 개수와 다르면 에러
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellData.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
        cell.textLabel?.text = cellData[indexPath.row]
        return cell
    }
    
}

UIKit에서는 위와 같이 Delegate 패턴이 사용되기 때문에 이 디자인 패턴에 익숙해져야겠다.

03. UItableviewDelegate 살펴보기

UITableViewDelegate, UITableViewDataSource

  • 실제로 해당 protocol의 내부 함수를 직접 보는 게 도움이 된다.
  • DataSource는 테이블 뷰가 이 데이터로 어떻게 그릴건지에 대한 메서드 위주
  • Delegate는 액션 위주 메서드

04. TableView로 간단한 화면 그리기

TodoViewController.swift

import UIKit

struct TodoItem {
    let title: String
    var isCompleted: Bool
}

class TodoViewController: UIViewController {

    @IBOutlet weak var todoTableView: UITableView!
    var data: [TodoItem] = [
        TodoItem(title: "커밋하기", isCompleted: false),
        TodoItem(title: "운동하기", isCompleted: true)
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .gray
        todoTableView.backgroundColor = .brown
        todoTableView.dataSource = self
        todoTableView.delegate = self
    }
    

}

extension TodoViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count;
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = todoTableView.dequeueReusableCell(withIdentifier: "todoCell", for: indexPath)
        
        cell.textLabel?.text = data[indexPath.row].title
        
        
        if data[indexPath.row].isCompleted {
            cell.textLabel?.textColor = .green
        } else {
            cell.textLabel?.textColor = .red
        }
        
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let myAction = UIContextualAction(style: .normal, title: "완료") {
            action, view, completionHandler in
            self.data[indexPath.row].isCompleted.toggle()
            self.todoTableView.reloadData()
            completionHandler(true)
        }
        return UISwipeActionsConfiguration(actions: [myAction])
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        todoTableView.deselectRow(at: indexPath, animated: true)
    }
    
    
    
}