[Day 42] iOS UITableView 셀이 보이지 않는 문제 해결 (ViewController와 View 인스턴스 참조 오류)
iOS 앱 개발 중 UITableView 셀이 보이지 않는 문제를 디버깅하고, ViewController와 View 인스턴스 참조 오류를 해결한 과정에 대한 TIL.
[Day 42] iOS UITableView 셀이 보이지 않는 문제 해결 (ViewController와 View 인스턴스 참조 오류)
오늘은 CurrencyCalculatorApp
프로젝트에서 UITableView
셀이 화면에 전혀 보이지 않는 문제로 인해 많은 시간을 보냈다. 테이블 뷰 자체는 화면에 잘 나타났지만, 그 안에 데이터가 채워진 셀은 아무리 디버깅해도 나타나지 않았다.
문제 현상
UITableView
는 화면에 정상적으로 표시됨.loadData()
함수를 통해 데이터(items
배열)는 163개로 정상적으로 로드됨.tableView.reloadData()
호출도 확인됨.UITableViewDataSource
의numberOfRowsInSection
은items.count
(163)를 반환함.- 하지만
tableView(_:cellForRowAt:)
메서드 내부의print
구문이 전혀 호출되지 않음. - 셀의 배경색이나 텍스트 색상을 변경해도 아무것도 보이지 않음.
디버깅 과정
- 데이터 로드 확인:
items
배열에 데이터가 정상적으로 들어오는지print
구문을 통해 확인했다. 결과는 163개의 데이터가 잘 로드되고 있었다. 이는 데이터 문제로 셀이 안 보이는 것이 아님을 의미했다. cellForRowAt
호출 여부 확인:tableView(_:cellForRowAt:)
메서드 내부에print
구문을 추가하여 이 메서드가 호출되는지 확인했다. 놀랍게도 아무것도 출력되지 않았다. 이는 테이블 뷰가 셀을 요청하지 않고 있다는 뜻이었다.- 델리게이트/데이터소스 설정 확인:
viewDidLoad()
에서self.currencyView.currencyTableView.delegate = self
와self.currencyView.currencyTableView.dataSource = self
가 설정되어 있음을 확인했다. 문법적으로는 문제가 없어 보였다. ViewController
와CurrencyView
인스턴스 불일치 의심:tableView(_:cellForRowAt:)
가 호출되지 않는다는 것은dataSource
가 제대로 연결되지 않았다는 강력한 증거였다.ViewController
의 초기화 부분을 다시 살펴보았다.
문제의 원인
문제는 ViewController
에서 CurrencyView
인스턴스를 다루는 방식에 있었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ViewController: UIViewController {
private var currencyView = CurrencyView() // (1) 여기서 CurrencyView 인스턴스 생성
override func loadView() {
view = CurrencyView() // (2) 여기서 또 다른 CurrencyView 인스턴스 생성하여 view에 할당
}
override func viewDidLoad() {
super.viewDidLoad()
// (3) currencyView 속성의 테이블 뷰에 델리게이트/데이터소스 설정
self.currencyView.currencyTableView.delegate = self
self.currencyView.currencyTableView.dataSource = self
loadData()
}
}
private var currencyView = CurrencyView()
:ViewController
의 속성으로CurrencyView
인스턴스가 하나 생성된다.override func loadView() { view = CurrencyView() }
:loadView()
는 뷰 컨트롤러의view
속성을 로드할 때 호출된다. 여기서 새로운CurrencyView
인스턴스를 생성하여view
에 할당한다.viewDidLoad()
에서self.currencyView.currencyTableView.delegate = self
:viewDidLoad()
에서는 (1)에서 생성된currencyView
속성의 테이블 뷰에 델리게이트와 데이터 소스를 설정한다.
결과적으로, 화면에 실제로 보이는 view
(2번 인스턴스)와 델리게이트/데이터 소스가 설정된 currencyView
속성 (1번 인스턴스)이 서로 다른 객체였던 것이다. 화면에 보이는 테이블 뷰는 델리게이트와 데이터 소스가 설정되지 않았으므로, cellForRowAt
메서드를 호출할 수 없었던 것이다.
해결책
문제는 ViewController
의 currencyView
속성과 view
속성이 서로 다른 CurrencyView
인스턴스를 참조하고 있었기 때문이었다. 이를 해결하기 위해 loadView()
메서드에서 view = CurrencyView()
대신, 이미 초기화된 currencyView
속성 인스턴스를 view
에 할당하도록 수정했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ViewController: UIViewController {
private let currencyService = CurrencyService()
private var currencyView = CurrencyView() // 기존과 동일하게 초기화
private var items: [CurrencyItem] = []
override func loadView() {
view = currencyView // 이미 초기화된 currencyView 인스턴스를 view에 할당
}
override func viewDidLoad() {
super.viewDidLoad()
// 이제 화면에 보이는 테이블 뷰에 델리게이트/데이터소스가 올바르게 설정됨
self.currencyView.currencyTableView.delegate = self
self.currencyView.currencyTableView.dataSource = self
loadData()
}
// ... 나머지 코드
}
이 수정으로 인해 ViewController
의 currencyView
속성과 view
속성이 동일한 CurrencyView
인스턴스를 참조하게 되었고, viewDidLoad()
에서 설정한 델리게이트와 데이터 소스가 화면에 보이는 테이블 뷰에 올바르게 적용되어 셀이 정상적으로 표시되었다.
배운 점
ViewController
에서view
를 커스텀 뷰로 설정할 때는loadView()
메서드 내에서view
에 할당하는 인스턴스와,ViewController
의 다른 속성으로 참조하는 인스턴스가 동일한 객체인지 항상 주의해야 한다.- 테이블 뷰 셀이 보이지 않을 때는 데이터 로드 문제뿐만 아니라, 델리게이트/데이터소스 연결, 뷰 계층 구조, 그리고 뷰 컨트롤러의 뷰 초기화 방식까지 폭넓게 디버깅해야 한다.
혹시 이 글을 보시는 분들 중 더 유용한 팁이 있다면 댓글로 많이 알려주세요!