Delete from CoreData not working on app retstart - swift

I have a function that deletes an NSManagedObject from CoreData (Test is a subclass of NSManagedObject:
public func delete(_ test: Test, completion: #escaping (Bool) -> Void) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return completion(false) }
let managedContext = appDelegate.persistentContainer.viewContext
do {
managedContext.delete(test)
completion(true)
} catch let error as NSError {
print("Could not delete. \(error), \(error.userInfo)")
completion(false)
}
}
Right now, it appears that the object is being deleted from CoreData in the moment, but if I rerun my app, the object that I just deleted appears again. What am I doing wrong when trying to delete this object?

You have to save the context to make changes persist, including deletions.
do {
try managedContext.save()
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}

Related

Cannot save removed items from list to core data

I'm fairly new to Swift and have an issue that I have not found an answer to on stack overflow. I'm sure I'm missing something stupid but cant figure it out. Help is appreciated.
I'm working on an app that allows the user to click on a button and add items to an array and click on another button and remove an item from the array. The array is being saved to core data. By clicking on the buttons I can successfully add and delete items to/from the array. When adding items to the array, I can also successfully save it to core data. The issue arises when I try and remove an item from the array. I use the context.save() but nothing saves. I believe this is because the viewContext does not record any changes. How do I force that? Note, this does not generate any errors in the catch blocks.
Here's the relevant code for the ViewController class
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let itemContext = (UIApplication.shared.delegate as! AppDelegate).persistentItemContainer.viewContext
var savedItems = [Item]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
do {
savedItems = try itemContext.fetch(Item.fetchRequest())
}
catch {
if let error = error as NSError? {
fatalError("Unresolved Error: 10003 \(error), \(error.userInfo)")
}
}
}
#IBAction func removeLastItem(_ sender: UIButton) {
savedItems.remove(at: savedItems.count-1)
appDelegate.saveItemContext()
}
Here's the relevant code for the AppDelegate class
lazy var persistentItemContainer: NSPersistentContainer = {
let itemContainer = NSPersistentContainer(name: "BlindedByTheLight")
itemContainer.loadPersistentStores(completionHandler: {
(storeDescription, error) in
print(storeDescription)
if let error = error as NSError? {
fatalError("Unresolved Error: 10001 \(error), \(error.userInfo)")
}
})
return itemContainer
}()
func saveItemContext(){
let itemContext = persistentItemContainer.viewContext
if itemContext.hasChanges {
do {
try itemContext.save()
}
catch {
if let error = error as NSError? {
fatalError("Unresolved Error: 10002 \(error), \(error.userInfo)")
}
}
}
}
You need delete object in your context:
let itemToDelete = savedItems[savedItems.count-1]
savedItems.remove(at: savedItems.count-1)
appDelegate.persistentItemContainer.viewContext.delete(itemToDelete)
appDelegate.saveItemContext()

UI is not updating when loading Data

During a loading-process I'm trying to update my UI (a label and a progress bar) from within a loop.
The UI is not updating though, until the loading-function is done.
The loading-function is not using another thread, I'm still in the main thread so from my understanding it should be possible to instantly-update the UI...
Is there something I am missing?
loading-function: (called from viewDidAppear)
func LoadDataFromDataCore(){
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "CDGlobeTile")
//3
do {
let DataCoreResult = try managedContext.fetch(fetchRequest)
var LabelFromCDArray = [LabelTile]()
for (index, CDGlobeTile) in DataCoreResult.enumerated() {
updateLoadingBar(Progress: Float(index) / Float(DataCoreResult.count - 1))
// "unpack" the data from CoreData...
}
do{
try managedContext.save()
} catch let error as NSError {
print("Error saving context. \(error), \(error.userInfo)")
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
print(" finished loading")
}
updateLoadingBar - function:
func updateLoadingBar(Progress: Float){
let percentage = Progress * 100
if let currentDispatch = OperationQueue.current?.underlyingQueue {
print(currentDispatch)
// this gives me "<OS_dispatch_queue_main: com.apple.main-thread>"
}
LoadingLabel.text = String(format: "%2.0f", percentage)
ProgressBar.progress = Progress
}

How to update looping data into core data?

I have tableView, and I already succeed saved it into core data (create new in core data).
When I update, it only update base on last data, not all data, and it cause the other data filled with the last data. so the result like this:
the actual is the first and the second tableView cell data different, but after update, it copy last data to other data.
This is my update code :
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequestPhone = NSFetchRequest<NSManagedObject>(entityName: "Phone")
do {
let phones = try managedContext.fetch(fetchRequestPhone)
if (phones.count > 0) {
for phone in phones {
phone.setValue(phoneNameValue, forKey: "phoneName")
phone.setValue(phoneNumberValue, forKey: "phoneNumber")
do{
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
What is the correct code to repair this?

Sync Core Data with server - same objects added multiple times

I have a list of categories that my user can choose. Since I am planning to add new categories without having to send a new update, I would like to load the new categories from my server every time a user launch the app. I came up with this code but every time it runs it keeps adding the same categories.
func loadDealCategory(){
let myUrl = NSURL(string: "\(ipAddress)/v1.0/dealCategory.php")
let request = NSMutableURLRequest(URL: myUrl!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{ data, response, error in
if error != nil {
print("error\(error)")
}else{
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSArray
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
for jsonDictionary in json {
// listing of columns in JSON seed file
let categoryDescription = jsonDictionary.valueForKey("category_description") as! String
print(categoryDescription)
let newCategory = NSEntityDescription.insertNewObjectForEntityForName("Categories", inManagedObjectContext: managedContext)
newCategory.setValue(categoryDescription, forKey: "category_description")
// I tried also format: "category_description = %#"
let fetchRequest = NSFetchRequest(entityName: "Categories")
fetchRequest.predicate = NSPredicate(format: "category_description LIKE %#", categoryDescription)
do {
let fetchResults = try managedContext.executeFetchRequest(fetchRequest)
print(fetchResults)
if fetchResults.count == 0{
do {
try managedContext.save()
//5
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}else{
print("\(categoryDescription) already exist!")
}
} catch let error as NSError {
// failure
print("Fetch failed: \(error.localizedDescription)")
}
}
} catch{
print("something went wrong loading json")
}
}
}
task.resume()
}
is it ok , loading it in func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
Found the problem, I was inserting the object before checking if it was already in the entity.
if fetchResults.count == 0{
let newCategory = NSEntityDescription.insertNewObjectForEntityForName("Categories", inManagedObjectContext: managedContext)
newCategory.setValue(categoryDescription, forKey: "category_description")
}else{
print("Could not save \(error), \(error.userInfo)")
}
and only then save
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}

How to test NSPersistentDocument in XCTestCase?

I'm just starting an OS X document-based app using Core Data. To test my model relationships, I'd like to create some NSManagedObject entities, save them to a file, and read them back in an XCTestCase object. Using code like below, I can create entities in the managed object context, but I cannot figure out how to create a functioning persistent store coordinator and/or save to a file.
class MyTests: XCTestCase {
var doc: Document!
var moc: NSManagedObjectContext!
//...//
override func setUp() {
super.setUp()
doc = Document()
moc = doc.managedObjectContext
}
//...//
}
Problem with my initial approach above was that I was getting the managedObjectContext before using configurePersistentStoreCoordinatorForURL. Once I resolved that, the solution was fairly straightforward.
class DocTests : XCTestCase {
let testFileURL = NSURL.fileURLWithPath("/Users/Me/Temp/DocTests", isDirectory: false)
override func setUp() {
super.setUp()
}
func testWriteAndRead() {
writeSimpleTestDocument()
let doc = Document()
do {
try doc.readFromURL(testFileURL, ofType: "mydoctype")
} catch let error as NSError {
print("Failed to read, \(error), \(error.userInfo)")
}
let moc = doc.managedObjectContext!
// fetch from moc and verify test entities here ...
// ...
}
func writeSimpleTestDocument() {
// if test document exists, delete it
let fm = NSFileManager.defaultManager()
if fm.fileExistsAtPath(testFileURL.path!) {
do {
try fm.removeItemAtURL(testFileURL)
} catch let error as NSError {
print("Failed to remove, \(error), \(error.userInfo)")
}
}
let doc = Document()
do {
try doc.configurePersistentStoreCoordinatorForURL(testFileURL, ofType: "mydoctype", modelConfiguration: nil, storeOptions: nil)
} catch let error as NSError {
print("Failed to configure coordinator, \(error), \(error.userInfo)")
}
let moc = doc.managedObjectContext!
// create test entities in moc here ...
// ...
do {
try moc.save()
} catch let error as NSError {
print("Failed to save, \(error), \(error.userInfo)")
}
}
}