Understanding Instance property vs parameter in Swift

Issue #72

The other day I was refactor my code. I have

1
2
3
4
5
6
7
8
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.

1
2
3
4
5
6
7
8
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.

1
2
3
4
5
6
7
8
9
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

1
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 😇

Comments