Browse Questions
- SOLID is a set of five design guidelines for maintainable OOP code: | Principle | Idea | Swift application | |--|--|--| | Single Responsibility | A type should have one reason to change | Split a…
- SOLID is five principles for writing maintainable, extensible code.
- View controller containment is the API for embedding one view controller inside another so the child keeps its own lifecycle.
- Delegation is a pattern where one object hands off responsibility to another through a protocol, letting a child communicate back to its owner without knowing its concrete type.
Answer:
View controller containment is the API for embedding one view controller inside another so the child keeps its own lifecycle. It requires a specific three-step sequence — addChild, add the view, then didMove(toParent:) — with a mirrored sequence for removal. It's how UINavigationController and UITabBarController are built, and how you break a large screen into independently owned pieces instead of a 1,000-line view controller.
Code Example:
extension UIViewController {
func add(_ child: UIViewController, to container: UIView) {
addChild(child) // 1. establish the parent-child relationship
container.addSubview(child.view) // 2. add the view and lay it out
child.view.frame = container.bounds
child.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
child.didMove(toParent: self) // 3. tell the child the move finished
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil) // 1. tell the child it's about to leave
view.removeFromSuperview() // 2. remove the view
removeFromParent() // 3. break the relationship
}
}
// Swapping content — e.g. loading → loaded → error states
func showState(_ state: State) {
children.forEach { $0.remove() }
switch state {
case .loading: add(LoadingViewController(), to: containerView)
case .loaded(let items): add(ListViewController(items: items), to: containerView)
case .error(let e): add(ErrorViewController(error: e), to: containerView)
}
}
// Hosting SwiftUI is containment too
let host = UIHostingController(rootView: ProfileView())
add(host, to: containerView)
Key Points:
- Skipping
addChild/didMovebreaksviewWillAppear, trait collection changes, rotation, andpreferredStatusBarStyleforwarding to the child - The asymmetry trips people up: adding calls
didMove(toParent:)at the end; removing callswillMove(toParent: nil)at the start (addChildandremoveFromParentcall the other half for you) - Use it for reusable sub-screens, state swapping, and hosting SwiftUI via
UIHostingController— not for anything that's just a view with no lifecycle needs - The parent strongly retains children in its
childrenarray, so alwaysremove()when swapping