
컨텐트에서 자식 뷰컨 제거하기
1. nil값을 사용해 willMove(toParent) 호출
2. 하위 루트 뷰에 대한 제약조건을 비활성화하거나 제거
3. 자식의 루트 뷰에서 removeFromSuperView() 호출해 뷰 계층구조에서 제거
4. 자식의 removeFromParent() 호출해 컨테이너-자식 관계 종료
UIContainerViewConteroller?
* 존재하지 않는 구현체이다. 컨테이너 뷰컨은 하나의 개념이며, 기존에 존재하는 클래스들을 이용해 커스텀 구현하면 된다.
전환할 탭 뷰 컨트롤러들을 배열에 담아두고, 인덱스를 통해 자식 뷰컨 추가 / 제거
구현 코드
final class MainTabBarController: UIViewController {
// 각 탭에 해당하는 자식 뷰 컨트롤러 리스트
private let childVCList = [
AViewController(),
BViewController(),
CViewController(),
DViewController()
]
private var selectedIndex = 0
private let tabBar = MainTabBar()
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
configureHierarchy()
setupFirstVC()
bind()
}
}
extension MainTabBarController {
private func configureHierarchy() {
[
tabBar
].forEach { view.addSubview($0) }
tabBar.snp.makeConstraints { make in
make.horizontalEdges.equalToSuperview()
make.bottom.equalToSuperview()
make.height.equalTo(100)
}
}
private func setupFirstVC() {
addChildVC(at: 0)
}
/// 탭바의 이벤트를 구독하고 처리
/// 탭 선택 시 해당하는 뷰 컨트롤러로 전환
private func bind() {
tabBar.tappedIndexRelay
.observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] index in
guard let self = self else { return }
guard index != self.selectedIndex else { return }
self.addChildVC(at: index)
self.removeChildVC(at: self.selectedIndex)
self.selectedIndex = index
})
.disposed(by: disposeBag)
}
}
extension MainTabBarController {
/// 지정된 인덱스의 자식 뷰 컨트롤러를 추가
/// - Parameter index: 추가할 뷰 컨트롤러의 인덱스
private func addChildVC(at index: Int) {
guard let vc = childVCList[safe: index] else {
AppLogger.error("Error: index out of range")
return
}
addChild(vc)
view.addSubview(vc.view)
vc.view.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
vc.didMove(toParent: self)
view.bringSubviewToFront(tabBar)
}
/// 지정된 인덱스의 자식 뷰 컨트롤러를 제거
/// - Parameter index: 제거할 뷰 컨트롤러의 인덱스
private func removeChildVC(at index: Int) {
guard let vc = childVCList[safe: index] else {
AppLogger.error("Error: index out of range")
return
}
vc.willMove(toParent: nil)
vc.view.snp.removeConstraints()
vc.view.removeFromSuperview()
vc.removeFromParent()
}
}
