Delete all entries [duplicate] - swift

This question already has answers here:
Delete/Reset all entries in Core Data?
(33 answers)
Closed 4 years ago.
I've been googling & stackoverflow'in but i can't find a solution for Swift4. I'm trying to delete all my entries in my core data database.
Heres my code
//Whats important
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Day", in: managedContext)!
//How i use it (might be completely unnecessary, just in case)
let fetchDay = NSFetchRequest<NSFetchRequestResult>(entityName: "Day")
fetchDay.fetchLimit = 1
let currentDay = try! managedContext.fetch(fetchDay)
let today: Day = currentDay.first as! Day
print("Date: \(today.date!)")
print("Completed: \(today.completed)")
No, my question is different. I will edit to explain how.
The delegate & context variables uses functions which is not available in swift4

You can delete all entries by many ways:
First
// Initialize Fetch Request
let fetchRequest = NSFetchRequest(entityName: "Item")
// Configure Fetch Request
fetchRequest.includesPropertyValues = false
do {
let items = try managedObjectContext.executeFetchRequest(fetchRequest) as! [NSManagedObject]
for item in items {
managedObjectContext.deleteObject(item)
}
// Save Changes
try managedObjectContext.save()
} catch {
// Error Handling
// ...
}
Second: Batch Delete Request:-
// Create Fetch Request
let fetchRequest = NSFetchRequest(entityName: "Item")
// Create Batch Delete Request
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try managedObjectContext.executeRequest(batchDeleteRequest)
} catch {
// Error Handling
}
Third: Deleting a Persistent Store:-
do {
try persistentStoreCoordinator.destroyPersistentStoreAtURL(persistentStoreURL, withType: NSSQLiteStoreType, options: nil)
} catch {
// Error Handling
}
You can find more info from: https://cocoacasts.com/how-to-delete-every-record-of-a-core-data-entity

Related

Empty Core Data Table

I would like to remove all data from a selected Core Data Entity. I'm using the below code but getting the following error:
Unresolved identifier managedObjectContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserAccountTbl")
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try managedObjectContext.executeRequest(batchDeleteRequest)
} catch {
// Error Handling
}
First of all – as already mentioned in the other answers – you have to get the NSManagedObjectContext from AppDelegate
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedObjectContext = appDelegate.persistentContainer.viewContext
Force unwrapping is perfectly fine, the application wouldn't even launch if AppDelegate was missing.
But there is a caveat:
If you call execute on the managed object context you have to merge the changes into the context because the execute operation doesn't modify the content of the context.
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserAccountTbl")
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
batchDeleteRequest.resultType = .resultTypeObjectIDs
do {
let result = try managedObjectContext.execute(batchDeleteRequest) as! NSBatchDeleteResult
let changes = [NSDeletedObjectsKey : result.result as! [NSManagedObjectID]]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [managedObjectContext])
} catch {
print(error)
}
However you can avoid the merge step if you call execute on the persistent store coordinator
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserAccountTbl")
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
let persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator!
try persistentStoreCoordinator.execute(batchDeleteRequest, with: managedObjectContext)
} catch {
print(error)
}
Seems like you haven't declared your managedObjectCotext and trying to access it. Try this:
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserAccountTbl")
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try managedObjectContext.executeRequest(batchDeleteRequest)
} catch {
// Error Handling
}
As from your error, you have not declare context from container which is in appDelegate. You can try with following code:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
//We need to create a context from this container
let managedObjectContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserAccountTbl")
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try managedObjectContext.executeRequest(batchDeleteRequest)
} catch {
// Error Handling
}

Core data not retaining older values

When I save to Core Data and then try to read from it, only the most recently saved value is retained.
The rest are nil when I try to print them out.
In my .xcdatamodeld, my entity is named CD_Cookbook and it has an attribute of name.
I'm not sure what I'm doing wrong.
func newCookbook(cookbook: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "CD_Cookbook", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
item.setValue(cookbook, forKey: "name")
do {
try managedContext.save()
}
catch {
print("did not save cookbook name to core data", error)
}
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "CD_Cookbook")
do {
let cd = try managedContext.fetch(fetchRequest)
print(cd)
}
catch {
print("Failed to fetch cookbook names from Core Data", error)
}
}
Instead of:
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "CD_Cookbook")
Do this instead:
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "CD_Cookbook")

Swift UIApplication.delegate must be used from main thread only

Xcode is complaining when I try to set the appDelegate & context variables, required in order to use CoreData.
Essentially, I would like to store the results of my Vision / CoreML image classification request into a Core Data database for offline analysis.
Seen related threads to this, and tried a bunch. Problem does not go away, and now (unknown to me!) the CoreData save errors after few hundred records. I am hoping removing this issue altogether will solve the error problem or I can troubleshoot it later...
This is specifically for debugging, and won't likely need CoreData when data analyses has finished.
Tried putting the variable declarations right at the top of the ViewController class, with appending "!" as I know I will be setting them later. Tried putting the 2 lines in a DispatchQueue.main.async closure.
Tried wrapping these 2 lines inside a "DispatchQueue.main.async({ })" line, but then I can no longer reference the context on the "newItem" lines. Wrapping the whole section does not work either, probably as the CoreData cannot see / access the data within the image request(?)
The code:
func processCameraBuffer(sampleBuffer: CMSampleBuffer) {
let coreMLModel = Inceptionv3()
if let model = try? VNCoreMLModel(for: coreMLModel.model) {
let request = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
if let results = request.results as? [VNClassificationObservation] {
var counter = 1
for classification in results {
let timestamp = NSDate().timeIntervalSince1970
// Purple Error is here
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newItem = NSEntityDescription.insertNewObject(forEntityName: "Predictions", into: context)
newItem.setValue(classification.confidence, forKey: "confidence")
newItem.setValue(classification.identifier, forKey: "identifier")
newItem.setValue(counter, forKey: "index")
newItem.setValue(timestamp, forKey: "timestamp")
newItem.setValue("inceptionv3", forKey: "mlmodel")
print("counter: \(counter) \(classification.identifier)")
do {
try context.save()
} catch {
print("CoreData Save error")
print(error.localizedDescription)
}
counter += 1
}
}
})
if let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
do {
try handler.perform([request])
} catch {
print(error.localizedDescription)
}
}
}
}
This is an annoying warning; however, it seems to be there for a reason as iOS wants to avoid deadlocks(???).
Using Swift 3, here's what I've found is a safe way to manage Core Data + AppDelegate (your mileage may vary):
DispatchQueue.main.async {
if let app = UIApplication.shared.delegate as? AppDelegate {
app.managedObjectContext.performAndWait {
// .. Core Data work here
// .. context.save()
} // app.managedObjectContext.performAndWait
} // if let app = UIApplication.shared.delegate as? AppDelegate
} // DispatchQueue.main.async
Hope this helps!

Update attribute for specific element using core data

I am working with core data to store different activities and keep track of how many times each activity has been performed. The entity is called "Activities" with attributes "name" and "total". When an activity has been performed more than once, I want to change the attribute "total" (By adding +1) for that specific activity, instead of adding a new activity. How can I do this? This is my code so far:
let appDel = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context: NSManagedObjectContext = appDel.managedObjectContext
let request = NSFetchRequest(entityName: "Activities")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format:"(name == %#)", name)
do {
let results = try context.executeFetchRequest(request) as! [Activities]
if results.count == 0 {
newActivity.setValue(1, forKey: "total")
newActivity.setValue(name), forKey: "name")
do {
try context.save()
}
catch {
print(error)
}
}
}
catch let error as NSError {
print(error)
}
}
If you want to update (if I am not mistaken), you can just change the total like this:
results.total = YourWantedNumber or results.setValue(YourWantedNumber, forKey: "total")
context.save()

Update all value in one attribute Core Data

I know how to fetch all value from one attribute in Core Data using an array. I just need to press a button and -1 all the value and save it back to the Core Data.
How can I update all the value once in swift?
Thanks.
For swift 3
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Params")
do{
if let fetchResults = try managedContext.fetch(request) as? [NSManagedObject] {
if fetchResults.count != 0 {
for index in 0...fetchResults.count-1 {
let managedObject = fetchResults[index]
managedObject.setValue("-1", forKey: "value")
}
try managedContext.save()
}
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
Try following example it might be helpful.Replace you entity name.
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Params")
var params = NSEntityDescription.insertNewObjectForEntityForName("Params", inManagedObjectContext: context) as! NSManagedObject
if let fetchResults = appDel.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [NSManagedObject] {
if fetchResults.count != 0{
for (var v = 0 ; v < fetchResults.count ; v++) {
var managedObject = fetchResults[v]
println(fetchResults)
managedObject.setValue("-1", forKey: "value")
context.save(nil)
}
}
}
While the question is quiet old, I am writing it for those who wish to do this task in a more optimized manner. According to the documentation,
Batch updates run faster than processing the Core Data entities yourself in code because they operate in the persistent store itself, at the SQL level.
Hence using NSBatchUpdateRequest is the best way to achieve the result. Here's a swift code that could do the job in the given scenario with using an extension to help simplify the code while also taking into account the fact that changes made in batch update are not reflected in the objects currently in memory.
extension NSManagedObjectContext {
/// Executes the given `NSBatchUpdateRequest` and directly merges the changes to bring the given managed object context up to date.
///
/// - Parameter batchUpdateRequest: The `NSBatchUpdateRequest` to execute.
/// - Throws: An error if anything went wrong executing the batch deletion.
public func executeAndMergeChanges(using batchUpdateRequest: NSBatchUpdateRequest) throws {
batchUpdateRequest.resultType = .updatedObjectIDsResultType
let result = try execute(batchUpdateRequest) as? NSBatchUpdateResult
let changes: [AnyHashable: Any] = [NSUpdatedObjectsKey: result?.result as? [NSManagedObjectID] ?? []]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
}
}
class MyCoreDataClass {
...
func updateAllParams() {
let request = NSBatchUpdateRequest(entityName: "Params")
request.propertiesToUpdate = ["value" : NSExpression(forConstantValue: -1)]
do {
try managedObjectContext.executeAndMergeChanges(using: request)
} catch {
print(error)
}
}
}
P.S: You need to be aware that validation rules enforced in data model are not considered while executing a batch update. According to the documentation,
When you use batch updates any validation rules that are a part of the data model are not enforced when the batch update is executed. Therefore, ensure that any changes caused by the batch update will continue to pass the validation rules.