Swift: Search for string in core data model - ios

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")

Related

Swift - Get one-to-many relationship

let's imagine that we have 2 entities:
-People (name, age, ..)
-House (color)
we recorded the data several times with house.addToPeople (newPeople) for each house
we want to get all the people of the house colored blue
how do we fetch this?
I tried this code but it gets all the people
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let peopleFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "People")
let houseFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "House")
houseFetch.fetchLimit = 1
houseFetch.predicate = NSPredicate(format: "color = %#", "blue")
...
let res = try? context.fetch(peopleFetch)
let resultData = res as! [People]
how to do this ?
Try this function. What it does is fetching all of the People and creating an array with all of the results.
func getAllItems() -> [People]? {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "People")
request.returnsObjectsAsFaults = false
do {
let result: NSArray = try context.fetch(request) as NSArray
return (result as? [People])!
} catch let error {
print("Errore recupero informazioni dal context \n \(error)")
}
return nil
}
If you want to perform your search following certain criteria such as a color, use the following code after request:
//Here i'm searching by index, if you need guidance for your case don't hesitate asking
request.predicate = NSPredicate(format: "index = %d", currentItem.index)
Edit: actually the code above is just to get all of the people, if you want to base your search on the houses do the following:
func retrieve()-> [People]{
//Fetch all of the houses with a certain name
let houseRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "House")
houseRequest.predicate = NSPredicate(format: "name = %#", "newName") //This seearch is by name
houseRequest.returnsObjectsAsFaults = false
do {
//put the fetched items in an array
let result: NSArray = try context.fetch(houseRequest) as NSArray
let houses = result as? [Houses]
//Get the people from the previous array
let people: [People]? = (houses.people!.allObjects as! [People])
return people
} catch let error {
print("Errore recupero informazioni dal context \n \((error))")
}
return nil
}
Thank you for your answer !
In this example "houses" is an array, so we have to add an index ➔ houses[0].people!.AllObjects
And thank you very much for your explanation.

Loading the results set for Core Data fetch request

I have a variable declared as such:
private var theText = String()
private var aId = String()
I then do a fetch request and want to load it into that variable:
let predicateA = NSPredicate(format: "active == %#", true as CVarArg);
let predicateB = NSPredicate(format: "theId == %#", aId);
let andPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.and, subpredicates: [predicateA, predicateB]);
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext;
let requestData = NSFetchRequest<NSFetchRequestResult>(entityName: "DataTable");
requestData.predicate = andPredicate;
do
{
let results = try context.fetch(requestData);
dataactivitiesid = results.first
// let resultset = results as! [NSManagedObject];
/* for data in results
{
// let testyId: Any? = (data as AnyObject).value(forKey: "testyId");
} */
}
catch
{
print("Error in fetching data");
}
Do I need to loop through the result set like in the code that is commented above or since I know it is only one row being returned can I use .first? Thanks in advance.
If you expect only one item you don't need a loop.
I recommend to optional bind the result of first to a variable which can be nil if no entry is found.
And you don't need a compound predicate, a single predicate can contain multiple conditions related to the same object.
And finally this is not Objective-C, remove the trailing semicolons.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext;
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "DataTable")
let predicate = NSPredicate(format: "active == TRUE AND theId == %#", aId)
fetchRequest.predicate = predicate
do {
if let result = try context.fetch(fetchRequest).first {
dataactivitiesid = result
}
} catch {
print(error) // print the actual error not a meaningless literal string
}

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)

How to delete values from core data in swift 2

for example here is the portion of my code that adds values
do {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "users")
let results = try context.executeFetchRequest(request)
if results.count > 0 {
for item in results as! [NSManagedObject] {
let fName = item.valueForKey("firstName")
let lName = item.valueForKey("lastName")
print(lName!, lName!)
}
}
} catch {
print("There was error getting data")
}
Let's say I have 10 users and now I want to
1. Delete users with lastName of "DOW"
2. First 2 users and last 2 users?
3. Also, all users with the lastName starts with "D"
Thanks
Borna
You can code:
if results.count > 0 {
for item in results as! [NSManagedObject] {
let fName = item.valueForKey("firstName") as! String
let lName = item.valueForKey("lastName")
print(lName!, lName!)
if fName.contains("DOW"){
appDelegate.managedObjectContext.deleteObject(item)
}
}
}
OR just get object what you want what NSPredicate and delete it
code:
let fetchRequest = NSFetchRequest(entityName: "users")
fetchRequest.predicate = NSPredicate(format: "firstName beginswith[c] %#", "D")
fetchRequest.returnsObjectsAsFaults = false
do{
let fetchResults = try appDelegate.managedObjectContext..executeFetchRequest(fetchRequest)
if fetchResults.count>0 {
appDelegate.managedObjectContext.deleteObject(fetchResults[0])
} else {
// no data
}
}catch{
//error
}
This question sounds like homework. The problem with deleting the first 2 and last 2 items is the data is stored unordered. You may get a different set of data from fetch request unless a sort order is provided.

Having trouble in filter array of dictionaries coming from server in swift

The dictionary coming from server is
{
data = ({
email = "a123#gmail.com";
phone = 9804504884;
"user_id" = 11;
username = abcd;
});
}
var dataArray:NSArray = dict.objectForKey("data") as! NSArray
println("names = ,\(dataArray)");
var pre:NSPredicate = NSPredicate(format: "username CONTAINS[c] a")
var result:NSArray = dataArray.filteredArrayUsingPredicate(pre)
println("names = ,\(result)");
I am always getting result blank result array from this swift code.
Please help me to resolve this issue.
Thanks
Do it like this,
let json = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
let predicate = NSPredicate(format: "username CONTAINS[C] 'a'")
if let filteredArray = json["data"]?.filteredArrayUsingPredicate(predicate) {
// do something with array
}
Note you should wrap your string inside single quotes ''.

Resources