iosswiftsirishortcutsappintents

"Find X" Action with Filter Option Accepting Dynamic AppEntity


I’m trying to extend my „Find XYZ“ action of my Reading-AppEntity to accept filtering for another Meter-AppEntity type. So basically I want to get all elements that have a Core Data relationship to the same object. Though, for some reason the filtering doesn’t work as expected and and ignores which AppEntity I select to filter for.

The Setup

In my database I have a Meter which has a relationship to Readings. I’ve bridged my Core Data entities to the AppEntity protocol, to use it in Shortcuts the following way:

struct ReadingEntity: AppEntity, Identifiable {
    var id: UUID
    
    @Property(title: "Value")
    var value: Double
    @Property(title: "Meter")
    var readingMeter: MeterEntity
    
    
    // Visual representation and other required stuff …
    
    // Create IntentEntity from Core Data Object
    init(from reading: Reading) {
        self.id = reading.wrappedID
        self.value = reading.value
        
        // Link to Meter
        if let meter = reading.meterRelationship {
            self.readingMeter = MeterEntity(from: meter)
        }
    }
}

struct MeterEntity: AppEntity, Identifiable {
    var id: UUID
    
    @Property(title: "Title")
    var title: String
    // …
    
    
    // Visual representation and other required stuff …
    
    // Create IntentEntity from Core Data Object
    init(from meter: Meter) {
        self.id = meter.wrappedID
        self.title = meter.wrappedTitle
    }
}

To support the Find Reading action I’ve implemented the filter options (besides the other required things):

struct ReadingIntentQuery: EntityPropertyQuery {
    // Other required functions

    // Filter Options
    static var properties = EntityQueryProperties {
        Property(\ ReadingEntity.$readingMeter) {
            EqualToComparator { NSPredicate(format: "readingMeter.id = %@", $0.id as CVarArg) }
        }
    }

    // Handling of Filtering
    func entities(
        matching comparators: [NSPredicate],
        mode: ComparatorMode,
        sortedBy: [EntityQuerySort< ReadingEntity >],
        limit: Int?
    ) async throws -> [ReadingEntity] {
        // Custom Predicate
        let predicate = NSCompoundPredicate(type: mode == .and ? .and : .or, subpredicates: comparators)

        // Custom sorting handling …
        
        return try IntentsDataHandler.shared.getReadings(matching: predicate, sortedBy: sortDescriptors, limit: limit)
    }
}

The Problem

The issue I’m having is, that no matter which Meter I select in the Find Reading dropdown-list, the EqualToComparator always returns the ID of the first Meter object in the dropdown-list. For some reason it even returns this first meter-ID, even when nothing is selected yet. Not sure why the selection in the filter action is ignored here …

Looks like a logic issue. Though, I don’t know what I’m doing wrong here. Maybe someone can help?


Solution

  • As mentioned in the comments, this was an issue introduced with iOS 17 and got fixed with iOS 17.2.
    The code above works fine now.