Search multi words in a single search iOS swift using NSPredicate - ios

I want to search a list by typing multi words from the detailed list.
e.g,
in a claim request list there are different type of lables such as amount, requestor name, request name and nos also. So i want to search anything from this label so that i can able to find the exact request.

var predicateList = [NSPredicate]()
let words = filterText.componentsSeparatedByString(" ")
for word in words{
if count(word)==0{
continue
}
let RequestTypeArray = NSPredicate(format: "RequestType contains[c] %#", word)
let RequestEmployeeArray = NSPredicate(format: "RequestorEmployee contains[c] %#", word)
let RegesterNumberArray = NSPredicate(format: "ReqNo contains[c] %#", word)
let AmountOrDaysArray = NSPredicate(format: "AmountOrDays contains[c] %#", word)
let orCompoundPredicate = NSCompoundPredicate(type: NSCompoundPredicateType.OrPredicateType, subpredicates: [firstNamePredicate, lastNamePredicate,departmentPredicate,jobTitlePredicate])
predicateList.append(orCompoundPredicate)
}
request.predicate = NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: predicateList)

May be this answer was helpful to you..
let addresspredicate = NSPredicate(format: "address_name contains[c] %#",searchText)
let accnopredicate = NSPredicate(format: "acc_no contains[c] %#",searchText)
let propertytype = NSPredicate(format: "property_type contains[c] %#",searchText)
let subpropertytypoe = NSPredicate(format: "subproperty_type contains[c] %#",searchText)
let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [addresspredicate,accnopredicate,propertytype,subpropertytypoe])
filteredProperty = (propertyArray as Array).filter { predicateCompound.evaluate(with: $0) };
print("filteredProperty = ,\(filteredProperty)")

Related

Searching with NSFetchResult Controller

I've been looking on how to search using a NSFetchResultController but most post I came across are from 2 years ago. Okay I'm trying to filter the objects, which in my case are Pokemon. Here is my function I'm using.
func attemptPokemonFetch(generation: String = "1", name: String = "") {
let context = coreData.persistentContainer.viewContext
let request: NSFetchRequest<Pokemon> = Pokemon.fetchRequest()
let sortByName = NSSortDescriptor(key: "id", ascending: true)
request.sortDescriptors = [sortByName]
request.predicate = NSPredicate(format: "generation = %#", generation)
if !name.isEmpty {
request.predicate = NSPredicate(format: "name CONTAINS[cd] %#", name)
}
let controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = self
self.controller = controller
do {
try controller.performFetch()
}
catch let err {
print(err)
}
}
I call this function in view did load, search bar did change text and when the segment changes index value. I know how to filter the Pokemon and use the searching. However the problem I come across is when I begin searching. When searching for a Pokemon in a specific generation other Pokemon from another generation will also appear. So I'll be at index 2 which is for generation 2 Pokemon and when searching, other Pokemon from different generation will be appearing. I'm not sure if its how I initialize the context. This is how my search bar function look like.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar == pokemonSearchBar {
let text = pokemonSearchBar.text!
self.attemptPokemonFetch(name: text)
collectionView.reloadData()
}
}
Another Example: Lets say I have 3 types of people some are skinny, normal and fat. When I'm at the index for skinny people I only want to search for people that are skinny not all the people. So what would I need to do to achieve this type of behavior.
Would really appreciate any help. :)
In your code
request.predicate = NSPredicate(format: "generation = %#", generation)
if !name.isEmpty {
request.predicate = NSPredicate(format: "name CONTAINS[cd] %#", name)
}
the second assignment replaces the previously assigned predicate.
What you probably want is
if name.isEmpty {
request.predicate = NSPredicate(format: "generation = %#", generation)
} else {
request.predicate = NSPredicate(format: "generation = %# AND name CONTAINS[cd] %#", generation, name)
}
A more flexible approach is to use NSCompoundPredicate:
var predicates = [NSPredicate]()
predicates.append(NSPredicate(format: "generation = %#", generation))
if !name.isEmpty {
predicates.append(NSPredicate(format: "name CONTAINS[cd] %#", name))
}
request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)

NSPredicate Formatting Issue

I'm creating an iOS app where I want the user to be able to search through a UITableView and display results based on a variety of different inputs. I'm using an NSPredicate with multiple conditions separated by "OR" to do this, but for some reason it's only searching with the first condition and none of the others.
Here's how my NSPredicate is formatted:
let searchPredicate = NSPredicate(format: "(SELF.firstName CONTAINS[c]
%#) OR (SELF.lastName CONTAINS[c] %#) OR (SELF.major CONTAINS[c] %#) OR
(SELF.year CONTAINS[c] %#) OR (SELF.gpa CONTAINS[c] %#)",
searchController.searchBar.text!)
My parameters are firstName, lastName, major, year, and gpa. When I type in anything besides the first name in the search bar, no results show up. But typing in a first name does indeed return matches. Why is this happening? Is my NSPredicate formatted incorrectly?
You have five instances of the %# format specifier in your predicate so you need to pass five values. You are only passing one.
You need to repeat searchController.searchBar.text! five times. BTW - assign that to a safely unwrapped variable and repeat that variable five times. It will be less typing.
if let srch = searchController.searchBar.text {
let searchPredicate = NSPredicate(format: "(SELF.firstName CONTAINS[c] %#) OR
(SELF.lastName CONTAINS[c] %#) OR
(SELF.major CONTAINS[c] %#) OR
(SELF.year CONTAINS[c] %#) OR
(SELF.gpa CONTAINS[c] %#)", srch, srch, srch, srch, srch)
...
}
if let text = searchController.searchBar.text, text.characters.count > 0{
var predicates = [NSPredicate]()
predicates.append(NSPredicate(format: "self.firstName CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.lastName CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.major CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.year CONTAINS[c]",text))
predicates.append(NSPredicate(format: "self.gpa CONTAINS[c]",text))
let searchPredicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
}
Not tested but this should work and is probably the simplest syntax for Swift if all your subpredicates are the same:
if let text = searchController.searchBar.text {
let myCompondPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: ["firstName", "lastName", "major", "year", "gpa"].map {
NSPredicate(format: "%K CONTAINS[c] %#", $0, text)
})
// Do something with myCompondPredicate here..
}
For a simple, static, predicate like this, I would opt for a native Swift approach:
import Foundation
struct Student {
let firstName: String
let lastName: String
let major: String
let gpa: Double
}
extension Student {
func anyFields(contain searchString: String) -> Bool {
return firstName.contains(searchString)
|| lastName.contains(searchString)
|| major.contains(searchString)
|| String(gpa).contains(searchString)
}
// Alternate implementation:
/*
func anyFields(contain searchString: String) -> Bool {
return [firstName, lastName, major, String(gpa)].contains(where: { field in
field.contains(searchString)
})
} */
}
let matchingStudents = students.filter(Student.anyFields(contain:))

Swift: Search for string in core data model

I'm confronted with the following problem in Swift.
I wrote the following function to retrieve all persons in my model with the name "David".
private func myFetchRequest()
{
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let myRequest = NSFetchRequest(entityName: "RegisterOfPersons")
myRequest.predicate = NSPredicate(format: "name = %#", "David")
do{
let results = try moc.executeFetchRequest(myRequest)
for result in results
{
print(result)
}
} catch let error{
print(error)
}
}
Even though my model contains two entries with the attribute name = "David", the line
myRequest.predicate = NSPredicate(format: "name = %#", "David")
does not find these entries, because "name" is an optional attribute in my model.
Do I have to search for Optional("David"), meaning something like myRequest.predicate = NSPredicate(format: "name = %#", Optional("David"))?
How can I search for all entries with the name "David" in my model? What am I doing wrong?
Thanks for your help!
You are predicating with string so enclose your comparison name with single quote like this
myRequest.predicate = NSPredicate(format: "name = '%#'", "David")
Also try with Contains
myRequest.predicate = NSPredicate(format: "name CONTAINS[cd] %#", "David")

Searching by object property with UISearchController?

In my updateSearchResultsForSearchController method, I have a searchPredicate that I use to find matches, however, I want to learn how to use it with an Object's property.
I have an object called Product that has a String property called title which I would like to use as my search parameter. So far, this is what my search function looks like:
func updateSearchResultsForSearchController(searchController: UISearchController) {
productSearchResults.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text)
let array = (orderGuideItemsList as NSArray).filteredArrayUsingPredicate(searchPredicate)
productSearchResults = array as! [Product]
self.tableView.reloadData()
}
where orderGuideItemsList is an array of Product objects
So is there a way for me to search based on Proudct's title property? It doesn't have to use a predicate but that's what I have from a previous tutorial.
Thanks!
You can update your predicate to
let searchPredicate = NSPredicate(format: "SELF.title CONTAINS[c] %#", searchController.searchBar.text)
This should work fine.

Adding to a NSCompoundPredicate

I want to make my code more reusable for core data, I have a fetchRequest with predicates that I always must use. However some methods require more conditions. I want to add those conditions to the predicate list however I am unsure how to do this. I would like a method to return a predicate with basic queries and then add on to those queries.
let fetchRequest = NSFetchRequest(entityName: "Stop")
var currentTime = NSDate.getTime()
var sort = NSSortDescriptor(key: "time", ascending: true) // sort by bus stop
fetchRequest.sortDescriptors = [sort]
let predicate = NSPredicate(format: "time >= %ld", currentTime)
let predicate2 = NSPredicate(format: "stop_name == %#", stop)
let predicate3 = NSPredicate(format: "busParent.direction == %#", direction)
let predicate4 = NSPredicate(format: "busParent.name == %#", name)
let predicate5 = NSPredicate(format: "busParent.schedule == %ld", schedule)
fetchRequest.predicate = NSCompoundPredicate.andPredicateWithSubpredicates(
[predicate, predicate2, predicate3, predicate4, predicate5])
// EXAMPLE: HOW WOULD I ADD TO THE COMPOUND PREDICATE ALREADY MADE?
fetchRequest.predicate.????
You can compound NSCompoundPredicates with other NSPredicates:
let currentPredicate = fetchRequest.predicate!
let additionalPredicate = NSPredicate(format: "whatever",...)
let nextPredicate = NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: [currentPredicate, additionalPredicate])
fetchRequest.predicate = nextPredicate
By specifying .AndPredicateType you will "narrow down" the existing results to those that also meet the additional predicate. But you could also specify OrPredicateType or NotPredicateType to add to or exclude (respectively) the existing results.

Resources