Compare string with CoreData - swift

I have a String (for example "Test") and I also have a few strings which are stored in CoreData. Now I'd like to check if the string "Test" also exists in CoreData. So I simply want to compare all strings which are saved in CoreData with the string "Test".
Does someone of you know how to do this in Swift?

I don't know of any one-line solution, however you can:
Fetch with predicate
See if the returned array is empty (it doesn't exist in core data) or not (element exists).
var request : NSFetchRequest = NSFetchRequest(entityName: "Core_Data_Entity");
request.predicate = NSPredicate(format: "Property_name = %#", #"Test")
var results : [NSManagedObject] = context.executeFetchRequest(request, error: nil) as [Core_Data_Entity]
if (results.count > 0) {
//Element exists
}
else {
//Doesn't exist
}

Related

how to save mixed sort?

From the list in which the words are located, I need to display them in a mixed state.
To do this, I added a shuffle sort field to the entity
func setShuffleWords(id: UUID?) -> [CoreWord]? {
guard let id = id else { return nil }
let requestWords = NSFetchRequest<NSFetchRequestResult>(entityName: "CoreWord")
requestWords.predicate = NSPredicate(format: "ANY dictionary.id == %#", id as CVarArg)
var coreWords: [CoreWord]?
if let result = try? managedContext.fetch(requestWords) as? [CoreWord] {
let words = result.shuffled()
for (index, value) in words.enumerated() {
if value.value(forKey: "shuffle") != nil {
value.setValue(index, forKey: "shuffle")
}
}
coreWords = words
}
save()
return coreWords
}
func getShuffleWords(id: UUID?) -> [CoreWord]? {
guard let id = id else { return nil }
let requestWords = NSFetchRequest<NSFetchRequestResult>(entityName: "CoreWord")
let sort = NSSortDescriptor(key: "shuffle", ascending: true)
requestWords.predicate = NSPredicate(format: "ANY dictionary.id == %#", id as CVarArg)
requestWords.sortDescriptors = [sort]
do {
let result = try managedContext.fetch(requestWords)
return result as? [CoreWord]
} catch let error {
fatalError(error.localizedDescription)
}
}
But, the problem is that if I mix up another list where this word is, then the value is rewritten and it will change its position everywhere.
How to keep mixed order in a specific list?
In this situation you need to replace your many-many relationship with an intermediate entity. Let’s call that entity a Listing. It will represent the listing of a particular word in a particular group, so each Listing should have a to-one relationship to CoreWord and a to-one relationship to CoreGroup. In each case the inverse (which you might call “listings”) should be to-many. The Listing entity should have (at least) one attribute, shuffle, which represents the sequence of a particular word on a particular group.
Life generally gets more complicated, because you have to create and manage these intermediate objects rather than just working the Word and Group objects and their relationships.

Filter querying multiple objects from Realm using List of Primary Keys

I'm trying to query multiple objects from Realm using a List of Primary Key Strings. I know I can do this using a for..in loop but I'd rather use a filter if possible.
primaryKeyArray contains a number of Strings
class Item : Object {
#objc dynamic var itemKey = NSUUID().uuidString
}
var primaryKeyArray : List<String>?
//Assume Realm DB already contains multiple Item Objects
//primaryKeyArray contains "key1", "key2", "key3", etc..
let predicate = NSPredicate(format: "itemKey == %#", primaryKeyArray)
let items = realm.objects(Item.self).filter(predicate)
I know the problem is with my predicate format. Not sure whether to use some form of CONTAINS or what? Any help with the predicate syntax would be greatly appreciated!
I think you are asking how to query Realm for items that have keys that match a set of keys in an array.
So given a DogClass Realm Object
class DogClass: Object {
#objc dynamic var dog_id = NSUUID().uuidString
#objc dynamic var dog_name = ""
override static func primaryKey() -> String? {
return "dog_id"
}
}
and suppose we know we want to retrieve three dogs that match some given primary keys
let keysToMatch = ["302AC133-3980-41F3-95E8-D3E7F639B769", "54ECC485-4910-44E5-98B9-0712BB99783E", "71FE403B-30CD-4E6C-B88A-D6FDBB08C509"]
let dogResults = realm.objects(DogClass.self).filter("dog_id IN %#", keysToMatch)
for dog in dogResults {
print(dog.dog_id, dog.dog_name)
}
Note the use of IN in the filter, which will match any dogs with id's in the given array.
You can also pass in a Realm List Object instead of a Swift array and get the same result.
let listOfKeysToMatch = List<String>()
listOfKeysToMatch.append("302AC133-3980-41F3-95E8-D3E7F639B769")
listOfKeysToMatch.append("54ECC485-4910-44E5-98B9-0712BB99783E")
listOfKeysToMatch.append("71FE403B-30CD-4E6C-B88A-D6FDBB08C509")
let dogResults2 = realm.objects(DogClass.self).filter("dog_id in %#", listOfKeysToMatch)
for dog in dogResults2 {
print(dog.dog_id, dog.dog_name)
}
let predicate = NSPredicate(format: "itemKey IN %#", primaryKeyArray)

Core data Fetch request on relationship properties

My app has a number of wordLists each of which contain a number of words. In one view controller a tableView lists the wordLists and then a sub view controller has a tableView with the words in it. The segue passes the wordList entity. But I cannot work out how to do a fetch request on the wordList passed to then get all the words. Error message is shown below. I need to do a fetch request rather than looking at properties so I can do a sort.
Thanks in advance for any help on this one....
The WordList entity has an attribute listName, and relationships: words, destination: Word, Inverse: wordList
The Word entity has an attribute wordName, wordIndex and relationships: wordList, destination: WordList, Inverse: words
My WordsViewController looks like:
class WordsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
var coreDataStack: CoreDataStack = (UIApplication.sharedApplication().delegate as! AppDelegate).coreDataStack
var wordList: WordList?
var words = [Word]()
var word: Word?
override func viewDidLoad() {
super.viewDidLoad()
// set the title of the scene
title = wordList?.listName
// fetch all the words that are part of the wordList passed to this VC.
let fetchRequest = NSFetchRequest(entityName: "Word")
let wordListPredicate = NSPredicate(format: "word.wordList == '\(wordList)'") // GIVES AN ERROR SAYING UNABLE TO PARSE THE FORMAT STRING "word.wordList == 'Optional(<WordList:0x...
let sortDescriptor = NSSortDescriptor(key: "wordIndex", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = wordListPredicate
do {
if let results = try coreDataStack.managedObjectContext.executeFetchRequest(fetchRequest) as? [Word] {
words = results
}
} catch {
fatalError("There was an error fetching system person")
}
}
You cannot use string interpolation to build a predicate, use
argument substitution instead. In your case (since var wordList: WordList? is an
optional):
if let theWordlist = wordlist {
let wordListPredicate = NSPredicate(format: "wordList == %#", theWordlist)
} else {
// wordlist is nil ...
}
Note also that "word.wordList == " in the predicate should be
"wordList == ", because "wordList" is the property of the "Word"
entity.
For more information, see Predicate Format String Syntax
in the "Predicate Programming Guide".
You should use a NSFetchedResultsController, not fetch all data in viewDidLoad. The fetched results controller will help you fetch and display the data efficiently, react to changes, optimize memory, etc.
In the fetched results controller's fetch request (which fetches entity Word), use this predicate (with a safeguard if your optional wordList is nil):
request.predicate = wordList != nil ?
NSPredicate(format: "wordlist = %#", wordList!) :
NSPredicate(value: false)
This assumes that there is a one-to-many relationship between word list and its words. I would recommend this setup, even if it implies that you might have to store the same word more than once if it is in different lists.
NB: the false predicate ensures you get a valid fetch request which will fetch nothing.

Searchbar with core data issues

I have a search bar.And data displayed in labels with scrollview.
For ex:
core data Fields :
1.id
2.company
3.Employe Name
4.Address
If i type id,company or Employee Name in searchbar i want to dispaly associated results.
my code :
For search data :
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
var request = NSFetchRequest(entityName: "Agency")
request.returnsObjectsAsFaults = false
var countResult : NSArray = context.executeFetchRequest(request, error: nil)!
let result = NSPredicate(format: "SELF CONTAINS[c] %#",searchText)
self.filtered = self.countResult.filteredArrayUsingPredicate(result!)
if (filtered.count == 0 ) {
searchActive = false;
}else {
searchActive = true;
}
println(filtered)
}
It shows an error " 'Can't use in/contains operator with collection".
These codes cannot satisfy what i want.And also i dont have a idea how to fetch the related rows according to enter value in search bar.
Thanks in Advance.
The first problem is your predicate - you're trying to use CONTAINS on an NSManagedObject subclass, but CONTAINS only works with String. To check whether your search text is contained within any of your managed objects you need to evaluate whether it is contained in each attribute (in your case id, company and empolyeeName, I'm assuming they're all Strings).
To do this you should change your predicate to:
let searchPredicate = NSPredicate(format: "id BEGINSWITH %# OR
company BEGINSWITH %# OR
employeeName BEGINSWITH %#",
searchText, searchText, searchText)
I would recommend using BEGINSWITH instead of CONTAINS[c] since when searching your user is likely to be entering the first part of the phrase. Also, as Apple said in their 2013 WWDC talk Core Data Performance Optimization and Debugging -
...we've got begins with and ends with and that's by far the cheapest query that you can execute.
...
Contains is more expensive because we have to work along and see
whether it contains...
And in the case of a search, you want it to be fast!
Secondly, you don't need to filter your results after getting them back from CoreData. You can set the predicate property on your NSFetchRequest and your returned results will be filtered. For example:
let request = NSFetchRequest(entityName: "Agency")
request.predicate = // Your predicate...
let results = context.executeFetchRequest(request, error)
// Now do what you need with the results.
A final note, it's best not to force unwrap your results from executeRequest in case there is some problem and nil is returned - in that case your app would crash. You could instead use:
if let unwrappedResults = results {
// Now do what you want with the unwrapped results.
}
I suspect it has something to do with your use of SELF in the predicate format, and the "collection" referred to in the error message is the controller sub/class within which your code resides.
Try something like this (forgive me I'm Obj-C not Swift so may have the syntax incorrect).
let searchAttribute = <<entity.attribute key path>>
let result = NSPredicate(format:"%K CONTAINS[cd] %#",searchAttribute, searchText)
Where %K refers to the key path, that in the case of Core Data is your entity attribute. For example: Agency.name if that attribute exists for your Agency object.
Read about Predicate Format String Syntax.
UPDATE after third comment...
In my apps my solution includes the creation of a custom method in an extension of the Core Data generated NSManagedObject subclass. If that sounds like you know what I mean, let me know and I will post details.
In the meantime, create a custom method in whatever class your UISearchBar is controlled... (apologies Obj-C not Swift)
- (NSString *)searchKey {
NSString *tempSearchKey = nil;
NSString *searchAtrribute1 = Agency.attribute1;
NSString *searchAtrribute2 = Agency.attribute2;
NSString *searchAtrribute3 = Agency.attribute3;
NSString *searchAtrribute4 = Agency.attribute4;
tempSearchKey = [NSString stringWithFormat:#"%# %# %# %#", searchAtrribute1, searchAtrribute2, searchAtrribute3, searchAtrribute4];
return tempSearchKey;
}
You'll obviously need a strong reference for your Agency entity object to persist within the class, otherwise you will need to embed this bit of code into your searchBar function.
Work OK?

NSPredicate with Swift and Core Data

i have a Core Data Object and i have 2 Fieds (one String(GUID) and one Int which i want to use as Filter)
So in SQL it would be "SELECT * FROM Answers WHERE qIndex = 1 AND GUID = '88bfd206-82fb-4dd0-b65d-096f8902855c'
Ive tried it with Core Data but i am not able to Filter with the String Value.
Here is my Code
var request = NSFetchRequest(entityName: "Answers")
request.returnsObjectsAsFaults = false;
let resultPredicate1 = NSPredicate(format: "qIndex = %i", qIndex)
let resultPredicate2 = NSPredicate(format: "formUUID = %s", formUUID)
var compound = NSCompoundPredicate.andPredicateWithSubpredicates([resultPredicate1, resultPredicate2])
request.predicate = compound
var results:NSArray = context.executeFetchRequest(request, error: nil)
Any ideas what i am doing Wrong? With the Same Code and Filter for 2 Integer Values it works fine.
Thanks in Advance
If formUUID is an NSString or a Swift String then you have to use the
%# placeholder:
let resultPredicate2 = NSPredicate(format: "formUUID = %#", formUUID)
This is not the exact response to your question, but a problem people might now encouter with your code now:
In the latest version of XCode, you must now unwrap the predicate, like this:
var compound = NSCompoundPredicate.andPredicateWithSubpredicates([predicate1!, predicate2!])
because NSPredicate initializer now return NSPredicate? type.
Instead of worrying about %# conversions and then composing AND predicates, you can use the PredicatePal framework:
let compound = *(Key("qIndex") == qIndex && Key("formUUID") == formUUID)
Assuming that qIndex and formUUID are the correct type, Swift will automatically deduce the correct types for the Key objects.