nsfetchedresultscontroller delete cache with name in swift - 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)

Related

NSSortDescriptor has no effect on Core Data fetch request

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)

Fetch one-to-many relationships in coreData and put it into a tableview

How can I fetch one-to-many relationships in core data and put it into a table view?
I have this as my data model for the User
User CoreData Data Model
And this is my data model for Task
Task CoreData Data Model
How can I fetch the tasks for a specific user and put it into a tableView
I tried using user.tasks, however that returned an NSSet and I couldn't use that to make a dataset for the table view.
Should I use predicate instead to do this? This is what I have
func handleCoreDataTask(){
let request: NSFetchRequest<Task> = Task.fetchRequest()
let dateSorter = NSSortDescriptor(key: "dueDate", ascending: false)
request.sortDescriptors = [dateSorter]
//request.predicate =
taskResultController = NSFetchedResultsController(fetchRequest: request,
managedObjectContext: coreDataStack.manageContext,
sectionNameKeyPath: nil,
cacheName: nil)
taskResultController.delegate = self
do{
try taskResultController.performFetch()
}
catch{
print("Perform Fetch error: \(error)")
}
}
Apply the inverse relationship to User in Task and add an appropriate predicate
let username = "Foo"
let request: NSFetchRequest<Task> = Task.fetchRequest()
request.predicate = NSPredicate(format: "user.name == %#", username)
let dateSorter = NSSortDescriptor(key: "dueDate", ascending: false)
request.sortDescriptors = [dateSorter]
The way to create a new results controller is discouraged. Create the results controller lazily (once) and change predicate and sort descriptors dynamically.

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]

Value of type 'NSFetchRequest' has no member 'performFetch'

I write code
var fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "Doctor")
fetchRequest.predicate = NSPredicate(format: "id != nil")
let sortDescriptors: [NSSortDescriptor] = [(NSSortDescriptor.init(key: "distance", ascending: true)), (NSSortDescriptor.init(key: "lastname", ascending: true))]
fetchRequest.sortDescriptors = sortDescriptors
var error: NSError? = nil
// show error Value of type 'NSFetchRequest' has no member 'performFetch'
var fetchSuccessful: Bool = fetchRequest.performFetch(error)
#Magdalena Dziesińska: In your code...
var fetchSuccessful: Bool = fetchRequest.performFetch(error)
"performFetch" does not exist. To handle the error (error handling) place it within a 'do-try-catch statement' e.g. after your code...
var fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "Doctor")
fetchRequest.predicate = NSPredicate(format: "id != nil")
let sortDescriptors: [NSSortDescriptor] = [(NSSortDescriptor.init(key: "distance", ascending: true)), (NSSortDescriptor.init(key: "lastname", ascending: true))]
fetchRequest.sortDescriptors = sortDescriptors
Use the following do-try-catch statement to catch any errors and get the fetch request.
do {
let results = try context.executeFetchRequest(request)
} catch {
print("requesting error")
}
nb: request is where you place your "fetchRequest"
You can not perform fetch request without context. If you have NSManagedObjectContext instance, you may use it executeFetchRequest(_:) method with your fetch request. More, if you have NSFetchedResultsController instance, initialized by your fetch request, you can use performFetch() method of this controller. You absolutely need to read more documentation of CoreData https://developer.apple.com/library/watchos/documentation/Cocoa/Conceptual/CoreData/index.html
What you're looking for is executeFetchRequest(_:) which throws rather than using taking an NSError param.
If the last non-block parameter of an Objective-C method is of type NSError **, Swift replaces it with the throws keyword, to indicate that the method can throw an error. If the Objective-C method’s error parameter is also its first parameter, Swift attempts to simplify the method name further, by removing the “WithError” or “AndReturnError” suffix, if present, from the first part of the selector. If another method is declared with the resulting selector, the method name is not changed. - Using Swift with Cocoa and Objective-C (Swift 2.2) - Error Handling

Sort descriptors with NSFetchedResultsController - Swift

I have a UITableView fed from Core Data with an NSFetchedResultsController returning the Location entities. The default sorting (and section headers) is via the first letter of the entity's name. This works (albeit I'm still trying to combine upper and lower case into the same section properly.) The user can choose to order the table by one of three optional categories (which are attributes of the entity) and then these categories are sorted by entity name.
When I set to sorting by category I get the following runtime error:
[_TtCSs23_ContiguousArrayStorage00007F80513B59D0 key]: unrecognized selector sent to instance 0x7f80513b5720
This is my NSFetchedResultsController:
var sectionNameKeyPathString1: String?
var sectionNameKeyPathString2: String?
var fetchedResultsController: NSFetchedResultsController {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("Location", inManagedObjectContext: self.managedObjectContext!)
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
if sectionNameKeyPathString1 != nil {
let sortDescriptor1 = NSSortDescriptor(key: sectionNameKeyPathString1!, ascending: true)
let sortDescriptor2 = NSSortDescriptor(key: sectionNameKeyPathString2!, ascending: true)
let sortDescriptors = [sortDescriptor1, sortDescriptor2]
fetchRequest.sortDescriptors = [sortDescriptors]
} else {
let sortDescriptor = NSSortDescriptor(key: "locationName", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
}
var sectionNameKeyPath: String
if sectionNameKeyPathString1 == nil {
sectionNameKeyPath = "firstLetterAsCap"
} else {
sectionNameKeyPath = sectionNameKeyPathString1!
}
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: sectionNameKeyPath, cacheName: "Locations")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
// TODO: Handle this error
// 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.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
return _fetchedResultsController!
}
Using breakpoints I am confident that, for example, sectionNameKeyPathString1 = "category1" and sectionNameKeyPathString2 = "locationName" and also that sectionNameKeyPath = "category1" so the key path matches the first sort descriptor.
I had this working in Obj-C but now I'm pulling my hair out and sure I'm suffering from bug-blindness.
Is it that you just have too many []?
let sortDescriptors = [sortDescriptor1, sortDescriptor2] // <- an [NSSortDescriptor]
fetchRequest.sortDescriptors = [sortDescriptors] // <- now an [[NSSortDescriptor]]
should just be:
fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2]