I have defined the following protocols:
protocol ListableArrayElement: Identifiable, Equatable {
associatedtype T = Hashable
var id:T { get }
}
protocol Listable: ObservableObject, RandomAccessCollection where Element == ArrayElement {
associatedtype ArrayElement: ListableArrayElement
var _elements: [ArrayElement] { get set }
var count: Int { get }
var isEmpty: Bool { get }
var endIndex: Int { get }
var startIndex: Int { get }
subscript(position: Int) -> ArrayElement { get set }
func index(after i: Int) -> Int
func append(_ element: ArrayElement)
func insert(_ newElement: ArrayElement, at i: Int)
func remove(at index: Int)
func removeAll()
func index(of element: ArrayElement) -> Int?
}
protocol FavouritesArray: Listable, Codable where Element: Codable {
// MARK: - PROPERTIES
var _elements: [Element] { get set }
var key: String { get set }
init()
init(key: String)
}
There is an associated extension to FavouritesArray that provides conforming types with the ability to add/remove elements, and persist/load the array to/from UserDefaults via the key. All well and good. (Also note the listable protocol helps me avoid writing some boiler plate code for ViewModels that have an array of 'something' at their heart.)
Now I also want to write a generic SwiftUI view that can build a menu, using the FavouriteArray functions. I am struggling to understand how to express the type signature:
I'm passing instances of types conforming to FavouritesArray via EnvironmentObject
, and thus want to write something like:
struct FavouritesArrayView<Favourites: FavouritesArray, Favourite>: View
where Favourite == FavouritesArray.Element {
@EnvironmentObject var favourites: Favourites
@ObservedObject var favourite: Favourite
// Other properties here
var body: some View {
// Layout code here
}
}
This gives the compiler error: Associated type 'Element' can only be used with a concrete type or generic parameter base
Any tips on how to achieve this?
CodePudding user response:
First of all you need to declare that Favourite
conforms to ObservableObject
and then the where
condition should use your associated type and not the protocol it conforms to, where Favourites.Element == Favourite
struct FavouritesArrayView<Favourites: FavouritesArray, Favourite: ObservableObject>: View where Favourites.Element == Favourite