Issue #72
The other day I was refactor my code. I have
extension MainController: TabBarViewDelegate {
func buttonDidPress index: Int) {
let initialIndex = tabBarView.selectedIndex
let wholeAppContentView = updateWholeAppContentView()
view.addSubview(wholeAppContentView)
}
}
The delegate method does not look right, as it’s hard to tell between required delegate method, or just instance method. Also it lacks a subject. I like this post API Design, you can read section Rule 19: Always say who’s talking
This is a simple rule, and an equally simple mistake to make. In your delegate methods, always pass the sender as a parameter. Always. Even for singletons. Even for things you cannot conceive would ever be used more than once simultaneously. No exceptions.
So I refactor the delegate, and conform to it.
extension MainController: TabBarViewDelegate {
func tabBarView(_ view: TabBarView, buttonDidPress index: Int) {
let initialIndex = tabBarView.selectedIndex
let wholeAppContentView = updateWholeAppContentView()
view.addSubview(wholeAppContentView) // This is the culprit ⚠️
}
}
Even with just 1 line change in MainController.swift
, the whole UI breaks, as all the views were added to the tab bar. Strange 😡 .
It didn’t take long until I remember that parameter
takes precedence over instance property
if they have same name. So in this case, the compiler, without warning, assume you’re dealing with view
from TabBarView
⚠️
That’s why you often use self
to disambiguate.
struct User: Codable, Equatable {
let firstName: String
let lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
Back to our code. The workaround is to specify self
to specify view
of MainController
self.view.addSubview(wholeAppContentView)
Well, you may say, who should add view again in case of tab bar changes 😬 This is a bad example, but the lesson is learned 😇