Using Swift 5.7 we're trying to use protocols for testing and mocking in our SwiftUI App.
With any
and some
we're able to hold a heterogeneous list of protocols with self constraints which works perfectly. What we're running into now is that we can't undox the any Protocol
into a concrete type for the view.
Here's a basic example:
protocol ItemProtocol: ObservableObject {
var id: String { get }
}
struct ListSection {
var id: Int
let title: String
let items: [any ItemProtocol]
}
protocol ViewModelProtocol: ObservableObject {
var sections: [ListSection] { get }
}
struct MyView<T: ViewModelProtocol>: View {
@ObservedObject
var viewModel: T
init(viewModel: T) {
self.viewModel = viewModel
}
var body: some View {
List(viewModel.sections, id: \.id) { section in
Section {
ForEach(section.items, id: \.id) { item in
RowView(item: item)
// create view for some ItemProtocol
Text("Hello Item")
}
} header: {
Text(section.title)
}
}
}
}
struct RowView<T: ItemProtocol>: View {
@ObservedObject
var item: T
init(item: T) {
self.item = item
}
var body: some View {
Text("Row View")
}
}
This will result in an error:
Type 'any ItemProtocol' cannot conform to 'ItemProtocol'
I had hoped that the any ItemProtocol
would be unboxed to it's concrete type and a concrete type of View would be created.
IMHO it would be best to define what you are testing. If you are testing business logic, then it would be best to test only the model without SwiftUI code. You can be guaranteed the dependent views will change when the model changes