How do I filter @Query with bound item

I have a few that is passed an item of type FamilyMember. Available in the view is a list of Chores. A chore has a member assigned to it. I want to filter the chores to the passed family member.

2 Structures and view code:

@Model
class Chore: Identifiable {
	@Attribute(.unique) var id = UUID()
	var name: String
	var frequency: ChoreFrequency
	var assignedTo: FamilyMember
	var isComplete: Bool
	var dueDate: Date

	init(id: UUID = UUID(), name: String = "", frequency: ChoreFrequency = .daily, assignedTo: FamilyMember = FamilyMember(), isComplete: Bool = false, dueDate: Date = Date()) {
		self.name = name
		self.frequency = frequency
		self.assignedTo = assignedTo
		self.isComplete = isComplete
		self.dueDate = dueDate
	}
}


@Model
class FamilyMember: Identifiable {
	@Attribute(.unique) var id: String { name }
	var name: String

	init(name: String = "Unassigned") {
		self.name = name
	}
}




struct MemberView: View {
	@Bindable var member: FamilyMember
	@Query private var chores: [Chore]

	init(member: FamilyMember) {
		self.member = member
		let predicate = #Predicate<Chore> {
			$0.assignedTo == member  // <— Error occurs here!
		}

		_chores = Query(filter: predicate, sort: \.dueDate)
	}

	.
	.
	.

It's when creating the predicate that I'm running to an error of value conversion. Cannot convert value of type 'PredicateExpressions.Equal<PredicateExpressions.KeyPath<PredicateExpressions.Variable<Chore>, FamilyMember>, PredicateExpressions.Value<FamilyMember>>' to closure result type 'any StandardPredicateExpression<Bool>'

What am I doing wrong?

  • FamilyMember has hashable extension

Add a Comment

Replies

In your Chore model class, you have the property assignedTo of type FamilyMember. Because you are using SwiftData, an implicit relationship is created. However, in order for the relationship to be complete it needs to have an inverse property in the other model. You need to add a property to FamilyMember that can be that inverse.

Here's an example of what it could look like:

@Model class Chore {
    @Relationship(inverse: \FamilyMember.chores) var assignedTo: FamilyMember
}

@Model class FamilyMember {
    @Relationship var chores: [Chore]
}

You could remove the Relationship macros and just have that chores property by itself and let SwiftData figure out the relationships, but I haven't tried this yet; it's best to do it yourself, plus you can visually see where the relationships are.


In my model classes, relationships are marked as optional, but that's just to satisfy CloudKit. I don't know if they have to be optional regardless (or have default values), but if you run into issues try doing that. Also, I am just guessing that the lack of an inverse property is your problem based off of your code. I haven't tested anything so feel free to let me know if I'm talking about the right stuff.

  • Thanks. I'll dig deeper into this and see if I can get it working.

Add a Comment