How to make protocol work in SwiftUI

Tonny
2 min readMay 4, 2022

SwiftUI view accepts several data types to render its content: raw types, State, Binding and ObservableObject (through StateObject or ObservedObject property wrapper). In ObservableObject conforming type, we usually use Published property wrapper to wrap the actual data for views. Besides these, are there any other ways?

You may want to display data in SwiftUI from a protocol like the following code, but Xcode shows errors, and you quickly end up with the idea that SwiftUI view does not work with protocol. Actually, SwiftUI view works very well with it, this is another way to provide data to view.

protocol ViewModelProtocol: AnyObject {
var image: UIImage { get }
var text: String { get }
func action()
}
struct Cell: View {
@ObservedObject var viewModel: ViewModelProtocol
var body: some View {
Button(action: viewModel.action) {
HStack {
Image(uiImage: viewModel.image)
Text(viewModel.text)
}
}
}
}

ObservedObject property wrapper requires the type must conform to ObservableObject protocol, but we require it to provide data from ViewModelProtocol. So we update the code with a generic which expresses these two purposes very clearly.


struct Cell<ViewModel: ObservableObject & ViewModelProtocol>: View {

@ObservedObject var viewModel: ViewModel

var body: some View {
Button(action: viewModel.action) {
HStack {
Image(uiImage: viewModel.image)
Text(viewModel.text)
}
}
}
}

Now let’s implement that abstract type on UserViewModel, it adopts both protocols. When the name property changes, the ObservedObject property wrapper will invalidate the above view, and ViewModelProtocol will serve the actual data to view.

class UserViewModel: ObservableObject {

@Published var name: String = "Text"
}extension UserViewModel: ViewModelProtocol {

var image: UIImage {
UIImage(systemName: "person")!
}

var text: String {
name
}

func action() {
name = "New text"
}
}
struct ContentView: View {
@ObservedObject var viewModel = UserViewModel()
var body: some View {
List {
Cell(viewModel: viewModel)
}
}
}

If you enjoy this story, please follow me to get more stories about Swift and app development.

--

--