Could Struct be a Delegate in Swift?

Yuta
Tech@Travelstart
Published in
2 min readMar 5, 2018

Delegate is a general design pattern in iOS. Here’s a simple example, we have AccountView and it needs someone to help it to update status, so we define a protocol AccountViewDelegate and make AccountView’s delegate ScreenViewModel to conform it.

Whole standard process is like below,

enum logInStatus {
case logIn
case logOut
}
protocol AccountViewDelegate: class {
func updateLoginStatus(_ status: logInStatus)
}
class AccountView: UIView {
var delegate: AccountViewDelegate?
func logInButtonDidPressed() {
delegate?.updateLoginStatus(.logIn)
}

func logOutButtonDidPressed() {
delegate?.updateStatus(.logOut)
}
}
class ScreenViewModel: AccountViewDelegate {
var status: logInStatus?
func updateLoginStatus(_ status: logInStatus) {
self.status = status
}
}
let accountView = AccountView()
let screenViewModel = ScreenViewModel()
screenViewModel.status = .logOut
accountView.delegate = screenViewModel
accountView.logInButtonDidPressed()
screenViewModel.status // logIn

As we can see, we usually set class as a delegate, but I wonder if we can set struct as a delegate? Let’s update the code above and explore how it works.

First, we remove the class constraint on AccountViewDelegate, the compiler will immediately show the warning, because property declaration attribute weak can only be used with class.

protocol AccountViewDelegate {
func updateLoginStatus(_ status: logInStatus)
}

Second, we remove previous class ScreenViewModel, new a struct with same name and make it conform AccountViewDelegate and implement function updateLoginStatus to change its status. To change property value in struct we need to mark delegate methond updateLoginStatusmutating, the updated code is like:

protocol AccountViewDelegate { 
mutating func updateLoginStatus(_ status: logInStatus)
}
struct ScreenViewModel: AccountViewDelegate {
var status: logInStatus
mutating func updateLoginStatus(_ status: logInStatus) {
self.status = status
}
}
let accountView = AccountView()
let screenViewModel = ScreenViewModel(status: .logOut)
accountView.delegate = screenViewModel
accountView.logInButtonDidPressed()
screenViewModel.status //logOut

After execution, screenViewModel status is still logout. Why is that? We did change the status. Because struct is value type, it copied when it’s assigned, in the moment, we have two ScreenViewModel, one is view’s property delegate, one is variable, we only change the delegate’s status, not the variable, it’s not the result we want.

It’s not appropriate to set struct as a delegate.

We want to clearly know which object execute the event, when we use struct, we will be confused the behavior that which object did, result will always in a copy of delegate.

--

--