NSSortDescriptor has no effect on Core Data fetch request - swift

My Core Data entity "Entry" has 4 attributes, including the attribute "key", which I want to sort by. "key" is non-optional and unique. Core Data structure:
I am fetching objects from Core Data like this:
var entries: [NSManagedObjectID : NSManagedObject] = [:]
class func fetchEntriesfromPersistentStore () {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Entry")
let sort = NSSortDescriptor(keyPath: \Entry.key, ascending: true)
fetchRequest.sortDescriptors = [sort]
do {
let fetchesEntries = try managedContext.fetch(fetchRequest)
entries = Dictionary(uniqueKeysWithValues: fetchesEntries.map{ ($0.objectID, $0) })
} catch let error as NSError {
print("Could not fetch entries. \(error), \(error.userInfo)")
}
}
I also tried the following initialisation of the NSSortDescriptor like in the official documentation:
let sort = NSSortDescriptor(key: "key", ascending: true)
The resulting dictionary is always in random order, i.e. in different order on every execution. I confirmed that code above is executed. Removing the NSSortDescriptor also has no effect on the results.
I inspected the list fetchesEntries before the objects are stored in the dictionary, and it is not sorted.
iOS Deployment Target is 13.4, Swift 5.0, Xcode 11.5, macOS 10.15.5

try
let sort = NSSortDescriptor(key: #keyPath(Entry.key), ascending: true)

Related

Distinct value from core data swift

i want to get distinct dates from core data.
with this code fetchRequest.returnsDistinctResults = true is not working.
it is still showing all values.
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Journal")
fetchRequest.propertiesToFetch = ["dateAsNumber"]
fetchRequest.returnsDistinctResults = true
do {
dateListSquare = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
If you want distinct results, you need to set the fetch request's result type to NSFetchRequestResultType.dictionaryResultType. You can't fetch managed objects and get distinct results, since there might be more than one managed object with the same value.
That would look something like
let fetchRequest: NSFetchRequest<NSDictionary> = NSFetchRequest(entityName: "Journal")
fetchRequest.propertiesToFetch = ["dateAsNumber"]
fetchRequest.returnsDistinctResults = true
fetchRequest.resultType = .dictionaryResultType
The result will be an array of dictionaries. Each will have one key per entry in propertiesToFetch (just one in this case).
If you use propertiesToFetch without dictionaryResultType, you affect how faulting works but not the contents of the result. Using returnsDistinctResults only works if you also use propertiesToFetch, so it's also affected by whether you use dictionaryResultType.

Is there performance difference between using sortDescriptors when retrieving from coreData vs. Array.sort?

Between 2 methods of getting a sorted array of NSManagedObject, which one is better? Or is there any performance difference between them?
/// Method 1: - use sortDescriptors
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Person.birthday), ascending: true)]
let results = try? coreDataStore.execute(fetchRequest)
return results as? [Person] ?? []
/// Method 2: - use Array.sort() on the returned result
let sortedPeople = results.sort({ ... })
Yes it is.
Core Data is optimized for performance. Sorting in Core Data is faster.

Sort by date - Swift 3

I have a func getData() which retrieves core data entity, and I want to sort them by date. How can I apply NSPredicate or Predicate to get the data from CoreData sorted by date?
My core data entity:
Entity: Expenses
Attributes:
amount
category
date
func getData() {
let context = appDelegate.persistentContainer.viewContext
do {
expenses = try context.fetch(Expenses.fetchRequest())
} catch {
print("Cannot fetch Expenses")
}
}
Predicates are for filtering your search results. To sort them you need to use an NSSortDescriptor. Assuming you have an attribute on your Expenses entity called date of type Date:
func getData() {
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Expenses>(entityName: "Expenses")
let sort = NSSortDescriptor(key: #keyPath(Expenses.date), ascending: true)
fetchRequest.sortDescriptors = [sort]
do {
expenses = try context.fetch(fetchRequest)
} catch {
print("Cannot fetch Expenses")
}
}
EDIT: I should have mentioned that the sort selector is added in an array so that multiple sort descriptors can be added if needed. e.g. sort first by date, then by number of legs, then by volume, etc.
You need a sort descriptor to get all the objects in a specific order.
let sectionSortDescriptor = NSSortDescriptor(key: "date", ascending: true)
let sortDescriptors = [sectionSortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
My function to do a fetchRequest of data in Core Data and sort the results by date "timestamp" in descending order. "Ruta" is the name of the entity.
//Array of Ruta entity
rutas = [Ruta]()
func getData() {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Ruta")
let sort = NSSortDescriptor(key: "timestamp", ascending: false)
request.sortDescriptors = [sort]
do {
rutas = try context.fetch(request) as! [Ruta]
} catch {
print("Fetching Failed")
}
}
In swift 4 or swift 5, you can use like
func sortlist(){
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "User")
let sort = NSSortDescriptor(key: "date", ascending: false)
fetchRequest.sortDescriptors = [sort]
//3
do {
let langugeCodes = try managedContext.fetch(fetchRequest)
for result in langugeCodes as [NSManagedObject] {
var username:String = result.value(forKey: "username")! as! String
print("username==>",username)
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
To get data which are lastly added at first, need to set key of sort descriptor as ObjectId.
let sectionSortDescriptor = NSSortDescriptor(key: #keyPath(Entity.ObjectId)
ascending: false) fetchRequest.sortDescriptors = [sectionSortDescriptor]

NSFetchRequest ReturnsDistinctResults gives empty results

I am trying to filter out the duplicate items in a result from a fetchRequest. I use the following code:
let sortDescriptor = NSSortDescriptor(key: "lastupdate", ascending: false)
let sortDescriptors = [sortDescriptor]
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext
let fetchRequest = NSFetchRequest(entityName:"Details")
fetchRequest.sortDescriptors = sortDescriptors
fetchRequest.propertiesToFetch = [ "orig_id" ]
fetchRequest.resultType = NSFetchRequestResultType.DictionaryResultType
fetchRequest.returnsDistinctResults = true
let company_temp = try context.executeFetchRequest(fetchRequest)
let company = company_temp as! [Details]
for t in company {
let id = t.orig_id
print(id)
self.myarray.append("\(id)")
}
When I comment out these 3 lines:
fetchRequest.propertiesToFetch = [ "orig_id" ]
fetchRequest.resultType = NSFetchRequestResultType.DictionaryResultType
fetchRequest.returnsDistinctResults = true
I get 8 items in my array. What is wrong with my code?
Did you save your context?
I had the same problem. When you have unsaved changes, the NSDictionaryResultType does not reflect the current state of the persistent store. See Apple Docs about the includesPendingChanges: method.
So a simple context.save() before your code might fixes your problem.
Another problem is that this line will crash: let company = company_temp as! [Details] since you'll get a Dictionary back. Not a list of NSManagedObject.

nsfetchedresultscontroller delete cache with name in swift

The title explains it already.
What is the swift code for deleting the cache from a nsfetchedresultscontroller.
This is the error i got:
You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:'
and the code:
if arranged == "naam - A-Z" {
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
self.fetchedResultsController.fetchRequest.sortDescriptors = [sortDescriptor]
}else if arranged == "naam - Z-A" {
let sortDescriptor = NSSortDescriptor(key: "name", ascending: false)
self.fetchedResultsController.fetchRequest.sortDescriptors = [sortDescriptor]
}else if arranged == "gemiddelde - 1-10" {
let sortDescriptor = NSSortDescriptor(key: "gemiddelde", ascending: true)
self.fetchedResultsController.fetchRequest.sortDescriptors = [sortDescriptor]
}else if arranged == "gemiddelde - 10-1" {
let sortDescriptor = NSSortDescriptor(key: "gemiddelde", ascending: false)
self.fetchedResultsController.fetchRequest.sortDescriptors = [sortDescriptor]
}
do {
try _fetchedResultsController!.performFetch()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
// print("Unresolved error \(error), \(error.userInfo)")
abort()
}
tableView.reloadData()
I you need any more information please let me know.
Update:
I want something like this:
fetchedResultsController.deleteCacheWithName("Master")
But i don't know how.
fetchedResultsController.deleteCacheWithName("Master")
does not compile because
public class func deleteCacheWithName(name: String?)
is a type function, it must be called on the type (class) itself,
not on an instance:
// Swift 2:
NSFetchedResultsController.deleteCacheWithName("Master")
// Swift 3:
NSFetchedResultsController<NSFetchRequestResult>.deleteCache(withName: "Master")
If you are using a cache, you must purge the cache before changing any of the fetch request, its predicate, or its sort descriptors.
Alternatively, you can create the fetched results controller
without using a cache:
NSFetchedResultsController(..., cacheName: nil)