Doms
Doms

Reputation: 93

CoreData NSPredicate

I converted one of old projects from Swift 1 to Swift 4.2 (in major version steps, all successfully built) which is using CoreData.

Now compiler throws error below when trying to execute this code:

let sortDescriptor = NSSortDescriptor(key: "dateModified", ascending: false)
let predicate = NSPredicate(format: "markAsDeleted == false")
if let itemInspections = item.inspections?.filtered(using: predicate).sortedArray(using: [sortDescriptor]) {
    label.text = "Items (\(itemInspections.count))"
}

Error:

2018-09-25 17:19:06.606722+0200 AppName[538:144354] -[_NSFaultingMutableSet filteredOrderedSetUsingPredicate:]: unrecognized selector sent to instance 0x17063afc0 2018-09-25 17:19:06.607861+0200 AppName[538:144354] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSFaultingMutableSet filteredOrderedSetUsingPredicate:]: unrecognized selector sent to instance 0x17063afc0'

*** First throw call stack: (0x18f5d6fd8 0x18e038538 0x18f5ddef4 0x18f5daf4c 0x18f4d6d2c 0x100126ce0 0x10015fa10 0x10015fc18 0x195ff9268 0x19575f884 0x19575a4ac 0x1956fc158 0x1928ec274 0x1928e0de8 0x1928e0ca8 0x19285c360 0x1928833c0 0x1956f17a0 0x18f5849a0 0x18f582628 0x18f582a74 0x18f4b2d94 0x190f1c074 0x195764130 0x100110cb4 0x18e4c159c)

libc++abi.dylib: terminating with uncaught exception of type NSException

Any pointer would be appreciated.

Upvotes: 0

Views: 262

Answers (3)

Doms
Doms

Reputation: 93

I ended up changing type of inspections to NSSet and explicitly casting result of filtered(using:_) -> changing the code like this:

let sortDescriptor = NSSortDescriptor(key: "dateModified", ascending: false)
let predicate = NSPredicate(format: "markAsDeleted == false")        
if let itemInspections = NSSet(set: (item.inspections?.filtered(using: predicate))!).sortedArray(using: [sortDescriptor]) as? [Inspection] {
    inspectionsCountLabel.text = "Inspections (\(itemInspections.count))"
}

Thanks for your comments, they pointed me in the right direction!

Upvotes: 0

vadian
vadian

Reputation: 285059

It's highly recommended to refetch the items with appropriate predicate and sort descriptor rather than do it manually.

The code assumes there is a NSManagedObject subclass Inspection with a relationship item and the Entity which is represented by item has a unique attribute name

let sortDescriptor = NSSortDescriptor(key: "dateModified", ascending: false)
let predicate = NSPredicate(format: "item.name == %@ AND markAsDeleted == FALSE", item.name)
let fetchRequest : NSFetchRequest<Inspection> = Inspection.fetchRequest()
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [sortDescriptor]
do {
    let itemInspections = try managedObjectContext.fetch(fetchRequest)
    label.text = "Items (\(itemInspections.count))"
} catch { print(error) }

And if you need only the number of filtered items there is a still more efficient API

let sortDescriptor = NSSortDescriptor(key: "dateModified", ascending: false)
let predicate = NSPredicate(format: "item.name == %@ AND markAsDeleted == FALSE", item.name)
let fetchRequest : NSFetchRequest<Inspection> = Inspection.fetchRequest()
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [sortDescriptor]
do {
    let numberOfItemInspections = try managedObjectContext.count(for: fetchRequest)
    label.text = "Items (\(numberOfItemInspections))"
} catch { print(error) }

Upvotes: 1

Modo Ltunzher
Modo Ltunzher

Reputation: 668

Try avoid explicit strings for entity attributes, also replace false with correct format expression:

let sortDescriptor = NSSortDescriptor(key: "\#keyPath(YourClassHere.dateModified)", ascending: false)
let predicate = NSPredicate(format: "\#keyPath(YourClassHere.markAsDeleted) == @%", NSNummber(value: false))
if let itemInspections = item.inspections?.filtered(using: predicate).sortedArray(using: [sortDescriptor]) {
    label.text = "Items (\(itemInspections.count))"
}

Upvotes: 0

Related Questions