Terje
1
Hi,
I have a protocol Record : PersistentModel and my model conforms to this protocol.
protocol Record : PersistentModel
{
var title: String { get }
}
@Model
final class TestModel
{
let title: String
}
extension TestModel : Record {}
I also have genetic view that takes a Record.
struct GenericView<Element> : View
where Element : PersistentModel & Record
{
@Environment(\.modelContext)
private var modelContext
@Query
var elements: [Element]
var body: some View
{
List
{
ForEach(elements)
{
Text("element: \($0.title)") //works fine
}
Spacer()
}
}
}
This all works fine until I try to set a filter on the query in a generic way:
init(_ : Element.Type = Element.self, keyword: String)
//where Element = TestModel //works fine if where clause is present
{
let filter = #Predicate<Element> { element in
return element.title.contains(keyword) //does not work without the where clause
//return true //always works
}
self._elements = Query(filter: filter)
}
The preview keeps crashing and the message says it can't find
TestModel.<computed ... (String)> on TestModel with PropertyMetadata(name: "title", keypath: \ TestModel.title,
Is this an issue that will always need to be worked around, something that will eventually be fixed/implemented in Swift or did I go wrong somewhere here?
lucab
(Luca Bartoletti)
2
I actually encountered the same exact problem. I find myself needing to make some fetching functions generic to avoid code duplication, but I end up with the same error
Couldn't find \MyType.<computed 0x0000000106269f70 (String)> on MyType with fields [...]
Can someone confirm if this is a bug or now?
lucab
(Luca Bartoletti)
3
I found a workaround for this
Before I had
func findCached<T: MyTypeProtocol>(with something: String) throws -> [T] {
let fetchDescriptor = FetchDescriptor<T>(
predicate: #Predicate {
$0.something == something
}
)
return try context.fetch(fetchDescriptor)
}
Now I don't have the generic type used in the FetchDescriptor. I kept all the generic reusable code I had before, but I also added the following to MyTypeProtocol
protocol MyTypeProtocol: PersistentModel {
// ...
static func fetchDescriptorForCachedItem(with: something: String) -> FetchDescriptor<Self>
}
I then implement that in every MyTypeProtocol adopter, where I can finally use a concrete type for the FetchDescriptor.
This approach seems to work, the findCached now looks like this
func findCached<T: MyTypeProtocol>(with something: String) throws -> [T] {
let fetchDescriptor = T.fetchDescriptorForCachedItem(with: something)
return try context.fetch(fetchDescriptor)
}
The draw back of this approach is that I need to duplicate the code in fetchDescriptorForCachedItem for every type conforming to MyTypeProtocol but I think is a good compromise given the fact that I manage to have a lot more reusable code in this way.
1 Like