내가 구현해야 하는 부분은 하단 tableView 이다.
우선 임의로 더미 데이터를 배열로 구성했다.
그리고 MenuDataViewController
class를 보면 3개의 프로토콜을 채택한 것이 보인다.
공부할겸 다시 각각에 대해 정리를 했다.
이 부분이 중요했던 게 ..
나는 이걸 공부했는데 delegate
또는 dataSource
를 설정하지 않으면
테이블 뷰가 데이터를 표시하지 않는다는걸 까먹고 채택하지않아 왜 뷰가 안나오나 했었기 때문.....
코드 실행 전에 delegate
와 dataSource
를 반드시 설정해야 한다는 점을 확인하고,
덕분에 tableView
와 관련된 프로퍼티를 viewDidLoad
에서만 초기화하는 것을 다시 점검했다.
UIViewController는 화면을 관리하는 뷰 컨트롤러 클래스다.
이 클래스를 상속받으면 화면을 구성하고, UI의 동작을 처리할 수 있다.
UIViewController
를 상속하는 이유는 이 클래스가 화면과 관련된 여러 작업을 처리할 수 있게 해주기 때문인데,
예를 들어 화면 전환, 뷰 초기화, 사용자 입력 처리 등을 할 수 있다는 것이다.
UITableViewDelegate는 UITableView
의 동작을 제어하는 데 필요한 메서드를 정의하는 프로토콜이다.
이 프로토콜을 채택하면 테이블 뷰의 행 선택, 셀의 높이 조정, 셀의 표시 방식 등을 제어할 수 있다.
이 프로토콜을 채택하는 이유는 테이블 뷰에서 사용자와의 상호작용을 다루기 위해서인데,
예를 들면 사용자가 셀을 선택했을 때 어떤 동작을 할지 결정하거나, 셀의 높이를 동적으로 설정할 수 있게 한다.
UITableViewDataSource는 UITableView
에 데이터를 공급하는 역할을 하는 프로토콜이다.
이 프로토콜을 채택하면 테이블 뷰에 표시할 데이터를 제공할 수 있다.
UITableViewDataSource
프로토콜을 채택하는 이유는 테이블 뷰의 행 수나 각 셀의 데이터를 제공해야 하기 때문이다.
이 프로토콜은 필수적인 메서드들을 정의하면서 데이터를 어떻게 테이블 뷰에 전달할지를 결정한다.
MenuDataViewController
클래스에서 테이블 뷰를 사용하고,
테이블 뷰의 동작과 데이터 제공을 모두 처리해야 하기 때문이라고 볼 수 있겠다.
UITableViewDataSource
는 테이블 뷰의 데이터 소스를 담당하고,
UITableViewDelegate
는 테이블 뷰의 동작을 제어하며,
UIViewController
는 화면을 관리하는 기본 클래스로, 이 세 가지 역할을 하나의 클래스에서 처리할 수 있게 된다.
그러니 테이블 뷰를 사용할 때 데이터 제공과 동작을 처리하려면
UITableViewDataSource
와 UITableViewDelegate
를 채택하고,
기본적으로 화면을 관리하려면 UIViewController
를 상속해야 한다는 점을 기억하자.
viewDidLoad()
메서드는 뷰 컨트롤러의 뷰가 로드된 후에 호출되는 메서드이다.
이 메서드에서 화면의 초기 설정과 레이아웃을 정의한다.
코드를 보면 우선 백그라운드 컬러는 ligthGray
색상으로 해주고,
view.addSubview(tableView)
는 테이블 뷰를 화면에 추가하는 코드다.
tableView
는 앞에 내가 정의한 테이블 뷰의 객체인데,
addSubview()
메서드를 사용해 현재 뷰에 추가된다.
그리고 tableView.delegate = self
와 tableView.dataSource = self
는
테이블 뷰의 동작을 설정하기 위해 필수로 해야 하는 코드다.
이걸 설정하지 않으면 테이블 뷰가 데이터를 어떻게 표시할지 그리고
사용자와 상호작용을 어떻게 처리할지 알 수 없기 때문이다.
이 부분은 테이블 뷰 셀을 재사용하기 위해 등록하는 코드인데,
register()
메서드를 사용해서 MenuTableViewCell
클래스를 MenuCell
이라는 셀 식별자와 함께 등록한다.
이 식별자는 테이블 뷰가 셀을 재사용할 때 사용된다.
register
메서드는 Xcode에서 제공하는 UITableView
의 메서드인데, 테이블 뷰에 셀을 등록하는 역할을 한다.
이 메서드는 재사용 가능한 셀을 등록할 때 사용되는데,
테이블 뷰가 데이터를 표시할 때 해당 셀을 효율적으로 재사용할 수 있도록 해준다고 알고있으면 된다.
tableView.rowHeight = 90
tableView.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.bottom.equalToSuperview()
make.top.equalToSuperview().offset(450)
}
그리고 tableView.rowHeight = 90
는 각 테이블 뷰 셀의 고정 높이를 설정하는 코드인데,
여기서는 각 셀의 높이를 90으로 지정했다.
tableView.snp.makeConstraints { make in ... }
이건 스냄킷을 사용해서 테이블 뷰의 레이아웃을 설정하는 부분인데,
make.leading.trailing.equalToSuperview()
는 좌우 끝이 부모 뷰에 맞춰지도록 했다.
make.bottom.equalToSuperview()
는 하단이 부모 뷰에 맞춰지도록 하고,
make.top.equalToSuperview().offset(450)
는 상단이 부모 뷰에서 450만큼 떨어지도록 설정했다.
이후 테이블 뷰의 크기를 동적으로 조정할 계획이 있기 때문에
동적인 높이 조정을 시도할 수 있도록
make.height.equalTo(tableView.contentSize.height)
코드도 주석으로 남겼다.
그리고 top.offset(450)
은 특정 상단 여백을 강제로 설정했기 때문에, 다른 화면 크기나 환경에서는 UI가 어색해질 수 있지만,
이 부분은 디바이스 크기와 상관없이 자동으로 맞춰지는 레이아웃을 구성하기 위해 safeArea
나 topLayoutGuide
를 사용하는 방안을 고려 중이다.
다른 팀원과 파일을 합칠 때 바로 사용이 되길 바란다... 제발 ㅎㅎ
tableView.reloadData()
이건 테이블 뷰의 데이터를 다시 로드하는 메서드인데,
이 메서드는 테이블 뷰가 화면에 표시되기 전에 데이터가 변경되었거나 업데이트가 필요할 때 사용된다.
데이터를 다시 로드하면 테이블 뷰가 갱신되어 새로운 데이터가 반영된다.
이거 안했다고 계속 햄버거 셀을 모두 삭제하면 튕기는 현상이 있었는데 이 코드가 해결해줬다.
아래 코드는 테이블 뷰에 표시할 셀의 수와 각 셀의 내용을 정의해주는 코드인데,
이 메서드는 테이블 뷰에게 각 섹션에 몇 개의 행 (row) 이 있어야 하는지 알려준다.
section
이 테이블 뷰의 섹션을 나타내는 파라미터고,
(여기서는 하나의 섹션만 사용하고 있다.)
return dummyBurgers.count
는 dummyBurgers 배열의 개수만큼 행(row)을 생성하도록 설정해준다.
dummyBurgers가 10개의 햄버거데이터를 가지고 있다면,
테이블 뷰는 10개의 셀을 표시하게 된다는 것.
위 코드의 역할은 테이블 뷰에게 특정 위치(indexPath)에 표시할 셀을 반환하고,
셀을 재사용 큐에서 가져오거나 새로운 셀을 생성해 반환해주는 역할이다.
자세히 보자면,
dequeueReusableCell(withIdentifier:for:)
는 테이블 뷰의 재사용 큐에서 셀을 가져오는 메서드다.
그리고 "MenuCell"
의 경우 셀을 등록할 때 사용한 식별자(reuseIdentifier) 라고 한다.
이 식별자를 통해 특정 셀을 가져올 수 있다는 점!
indexPath
는 셀의 위치를 나타내는 값으로 section
과 row
를 포함하고,
as? MenuTableViewCell
은 MenuTableViewCell
타입으로 셀을 캐스팅한다는 코드다.
만약 캐스팅에 실패하면 기본 UITableViewCell
을 반환하여 안전성을 확보해줘야한다.
그리고 indexPath.row
는 현재 행(row)의 인덱스를 나타내는 것인데,
dummyBurgers[indexPath.row]
는 dummyBurgers
배열에서 해당 인덱스에 해당하는 데이터를 가져온다.
이제 첫 번째 행에서는 dummyBurgers[0]
이 반환되고,
두 번째 행에서는 dummyBurgers[1]
이 반환된다.
numberOfRowsInSection
은 테이블 뷰에 몇 개의 행(row)을 표시할지 정의해주는 거고,
cellForRowAt
은 각 행에 표시할 데이터를 설정하고 재사용 가능한 셀을 반환하는 것,
그리고 여기서는 dummyBurgers
배열의 데이터를 사용해 각 셀의 데이터를 채운다는 것.
기억에 남는게 numberOfRowsInSection
과 cellForRowAt
메서드를 통해 데이터를 테이블 뷰와 연결해주면서
뭔가 테이블 뷰의 동작 방식을 좀더 명확히 이해할 수 있던 시간이었다.
cellForRowAt
에서 셀을 재사용하는건 효율성 면에서도 중요한 부분이긴 했는데,
이 과정에서 데이터와 UI가 자연스럽게 연결된다는 점을 또 한번 깨달았다.
특히, 커스텀 셀(MenuTableViewCell)을 캐스팅하고 데이터를 바인딩하면서 뷰와 데이터를 연결하는 과정이 걱정과 다르게 잘 된 것 같아서 뿌듯하다.
그리고 단순한 구조처럼 보이지만 delegate, dataSource, 그리고 레이아웃 설정 등 세부적인 부분까지 신경 써야 제대로 동작한다는 것도 다시금 깨달았고...
테이블 뷰는 기본이지만 강력하다는걸 실감한 날이다.
다음 이어서 또 작성해보겠다.
compose랑 비슷해서 흥미롭네요