FetchedResultsController Using Predicate to Exclude Results Contained in a Set

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


FetchedResultsController Using Predicate to Exclude Results Contained in a Set



I am attempting to filter the items in my FetchedResultsController to filter out a certain set of items. These are engines which have a certain letter designation in them followed by numbers. The possible rage of letters in the designation are from "A" to "O". I would like to be able to filter out engines that have the designations from "D" to "O" based on another condition.



I set a constant "highPowerEngines" that is a set containing those letters. Since the designation only contains one letter, I want to exclude any designation that contains any of the letters in highPowerEngines. So far, this is my code, the predicate I am working on is contained after the FIXME:


func configureFetchedResultsController() {
let context = databaseController.getContext()
let enginesFetchRequest = NSFetchRequest<Engine>(entityName: CoreData.engine)
let highPowerEngines: Set = ["D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]

var predicate = NSPredicate()
if currentStage == 1 && stages! == 1 {
predicate = NSPredicate(format: "engineType == %@", EngineType.singleStage.rawValue)
} else if currentStage < stages! {
predicate = NSPredicate(format: "engineType == %@", EngineType.boosterStage.rawValue)
} else {
predicate = NSPredicate(format: "engineType == %@", EngineType.upperStage.rawValue)
}

var predicateArray:[NSPredicate] = [
predicate
]
// FIXME: Sort out highPowerEngines
if !dPlusEngineIAP {
if currentStage == 1 && stages! == 1 {
predicate = NSPredicate(format: "NOT engineDesignation CONTAINS %@", highPowerEngines)
predicateArray.append(predicate)
}
}

let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
enginesFetchRequest.predicate = compoundPredicate

let primarySortDescriptor = NSSortDescriptor(key: CoreData.isMadeByName, ascending: true)
let secondarySortDescriptor = NSSortDescriptor(key: CoreData.engineDesignation, ascending: true)
enginesFetchRequest.sortDescriptors = [primarySortDescriptor, secondarySortDescriptor]


self.fetchedResultsController = NSFetchedResultsController<Engine>(
fetchRequest: enginesFetchRequest,
managedObjectContext: context,
sectionNameKeyPath: CoreData.isMadeByName,
cacheName: nil)

self.fetchedResultsController.delegate = self

}




2 Answers
2



Use IN instead of CONTAINS


NOT (engineDesignation IN %@)



update



Since you want to exclude all but tree letters why not turn the predicate around to include rather than exclude, something like


engineDesignation BEGINSWITH ‘A’ OR
engineDesignation BEGINSWITH ‘B’ OR
engineDesignation BEGINSWITH ‘C’





It isn't excluding the high power engines. I put a breakpoint in and it is definitely executing the code. Any thoughts?
– Yrb
Jul 23 at 18:32





Also, engineDesignation is a string that is a letter followed by other non-letter characters, if that changes things.
– Yrb
Jul 23 at 18:42





If it begins with a letter you should be using BEGINSWITH but I’m pretty sure that won’t work with a Set and I don’t really see any solution then that would work with a collection of letters apart from creating a massive compound OR predicate and checking each letter separately.
– Joakim Danielson
Jul 23 at 19:25







@Yrb I updated my answer with an alternative solution
– Joakim Danielson
Jul 23 at 19:34





No joy. it can't parse it with the "or"s. And you are right, BEGINSWITH doesn't work with a set or an array. Can I tell you I really hate string literals in predicates?!?
– Yrb
2 days ago



Thanks to the post here: CoreData Predicate get every sentence that contains any word in array
, I was finally able to solve my problem. My current working code is here:


func configureFetchedResultsController() {
let context = databaseController.getContext()
let enginesFetchRequest = NSFetchRequest<Engine>(entityName: CoreData.engine)
let lowPowerEngines = ["A", "B", "C"]

var predicate = NSPredicate()
if currentStage == 1 && stages! == 1 {
predicate = NSPredicate(format: "engineType == %@", EngineType.singleStage.rawValue)
} else if currentStage < stages! {
predicate = NSPredicate(format: "engineType == %@", EngineType.boosterStage.rawValue)
} else {
predicate = NSPredicate(format: "engineType == %@", EngineType.upperStage.rawValue)
}

var predicateArray:[NSPredicate] = [
predicate
]

if !dPlusEngineIAP {
let predicates = lowPowerEngines.map {
NSPredicate(format: "engineDesignation CONTAINS %@", $0)
}
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
predicateArray.append(predicate)
}

let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
enginesFetchRequest.predicate = compoundPredicate

let primarySortDescriptor = NSSortDescriptor(key: CoreData.isMadeByName, ascending: true)
let secondarySortDescriptor = NSSortDescriptor(key: CoreData.engineDesignation, ascending: true)
enginesFetchRequest.sortDescriptors = [primarySortDescriptor, secondarySortDescriptor]


self.fetchedResultsController = NSFetchedResultsController<Engine>(
fetchRequest: enginesFetchRequest,
managedObjectContext: context,
sectionNameKeyPath: CoreData.isMadeByName,
cacheName: nil)

self.fetchedResultsController.delegate = self

}



The solution to dealing with each item in the array was to make a compound predicate using the map function. Then adding the compound predicate to the fetchedResultsController. That allows me to compare the engine to see if it is in lowPowerEngines. Map makes a separate predicate for each item in lowPowerEngines. I could even change it programmatically on the fly. I really hope this helps someone as there is no central place to come up with these sort of tricks. When I collect enough of them, I will do a master post.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Makefile test if variable is not empty

Will Oldham

Visual Studio Code: How to configure includePath for better IntelliSense results