내용 정리
프로젝트를 진행하며
UIStackView와 관련된 UI 버그를 수정해보자.
프로젝트의 UI와 로직을 구현한 후 작성한 로직이 잘 작동하는지 확인하며 UI의 계층 구조 확인을 위해 Hierarchy를 확인해 보았는데 아래 사진과 같은 계층 구조를 이루고 있었다.

요일을 표현하는 스택뷰가 이상하게 중첩된 모습을 볼 수 있다.
이 상황도 처음 앱을 실행할 때부터 이런 모습이 아니라, 컬렉션뷰를 스크롤하면 발생하는 현상이었다.
왜 이런 현상이 발생했는지 원인을 분석하고 해결해보자.
요일을 표현하는 UI는 UIStackView로 구현되어 있으며, 컬렉션뷰 셀에 종속되어 있기 때문에 셀이 재사용될 때마다 다시 생성되는 과정을 거친다.
게다가 UI 버그도 셀이 재사용 되는 경우 발생했기 때문에 셀이 재사용되는 순간에 버그가 있다고 생각했다.
// 셀 재사용 옵션
override func prepareForReuse() {
super.prepareForReuse()
self.disposeBag = DisposeBag()
prepareForReuseData()
bind()
}
func prepareForReuseData() {
self.weekdaysStatus.accept([])
self.timeLabel.text = ""
self.note.text = ""
}
위 코드가 셀 재사용시 실행되는 메소드이다.
여기서 weekDaysStatus라는 옵저버블에 빈 배열([])을 보내 초기화를 시키는데, 이 부분이 요일의 스택뷰를 표현하는 데이터 부분이다.
배열의 값을 기준으로 월~일 요일을 표시하는 label을 만들고 스택뷰에 추가하는 과정을 거치는 것이다.
혹시 이 부분에서 빈 값을 이벤트로 방출해서 오류가 발생하는걸까 싶어서 값을 넣어서 테스트를 진행해 보았다.
func prepareForReuseData() {
self.weekdaysStatus.accept([Bool](repeating: false, count: 7))
self.timeLabel.text = ""
self.note.text = ""
}
요일을 표시하는 스택의 데이터는 [Bool] 형태의 데이터이고, 월~일 까지 요일의 수는 7개이기 때문에 7개의 false 데이터를 이벤트로 방출시켜 보았다.
그러나 달라지는 것은 없었다.
그럼 뭐가 문제일까 곰곰히 생각해 보다가, UI의 중첩 상황을 다시 보니 중첩이 되었다는건 기존의 뷰가 제거가 안된건 아닐까? 하는 생각이 들었다.
셀이 새로고침 될 때마다 스택뷰는 내부의 서브뷰를 모두 제거하고 새로운 데이터로 새로운 서브뷰를 추가하도록 로직을 구현하였다.
/// 아이콘을 다시 생성하는 메소드
/// - Parameter data: 아이콘 생성을 위한 데이터
func reloadIcons(data: [Bool]) {
self.stack.arrangedSubviews.forEach { subView in
self.stack.removeArrangedSubview(subView)
}
self.weekDays = data
setupIcons()
}
위의 코드가 셀 재사용 시 호출되는 코드이고, setupIcons()메소드가 스택뷰에 새로운 서브뷰를 추가하는 메소드이다.
여기서 분명 forEach를 사용해 스택뷰의 서브뷰를 모두 제거해 주었는데...
혹시 하는 마음에 코드를 한 줄 추가했다.
/// 아이콘을 다시 생성하는 메소드
/// - Parameter data: 아이콘 생성을 위한 데이터
func reloadIcons(data: [Bool]) {
self.stack.arrangedSubviews.forEach { subView in
self.stack.removeArrangedSubview(subView)
subView.removeFromSuperview()
}
self.weekDays = data
setupIcons()
}
바로 서브뷰의 슈퍼뷰를 제거하는 코드이다.
내가 생각한 것은 스택뷰는 서브뷰를 제거하여 참조하지 않게 되었지만, 서브뷰는 아직 스택뷰를 참조하고 있는 상태가 되어 UI가 중첩되는 그런 버그가 발생한게 아닐까? 생각했다.
그리고 이 상태로 빌드를 돌려 테스트를 해보았는데...

아까와 달리 중첩되는 버그가 사라진 모습을 볼 수 있었다.
코드 한 줄로 해결이 되니 약간 허무하게 느껴졌다...(꽤 시간을 많이 소모했기 때문에...)
그래도 앞으로 스택뷰를 동적으로 사용할 때 주의점에 대해 알 수 있었던 뜻 깊은 트러블 슈팅이었다고 생각한다.
오늘 트러블슈팅에 대한 결론을 정리하자면 아래와 같다.
UIStackView는 서브뷰의 관리와 오토 레이아웃 처리에 신중해야 한다.removeArrangedSubview(_:) 뿐만 아니라 removeFromSuperview()를 함께 사용하여 완전히 제거해 주어야 한다.기초적인 부분에서 버그가 발생해서 창피하다.