Switch view controller works if no other buttons are pressed - swift

I have a view that has a user input server info and on submit switches to another view. It works fine if they just hit submit. I have another button that is used to clear the saved server info if they wanted to change it at some point. The issue is that it doesn't work if the resetServerInfo button is pressed prior to the submit button.
User flow that works: Enter server name/Server IP -> testConnection -> submitServer -> Switches view controller
When it fails: clearServerInformation -> Enter server name/Server IP -> testConnection connection -> Submit -> Doesn't do anything
The code:
class serverSelect: UIViewController {
#IBOutlet var serverNameField: UITextField!
#IBOutlet var serverIPField: UITextField!
#IBOutlet var successLabel: UILabel!
#IBOutlet var errorLabel: UILabel!
//Submit button - checks fields aren't empty, then saves info to core data
#IBAction func submitServer(sender: UIButton) {
errorLabel.hidden = true
if(!serverNameField.text!.isEmpty && !serverIPField.text!.isEmpty){
saveName(serverNameField.text!, ip: serverIPField.text!)
switchToViewController("userselect")
}
else {
errorLabel.text = "Fields must contain data"
errorLabel.hidden = false
}
}
//Calls deleteserverinformation on button click
#IBAction func resetServerInfo(sender: UIButton) {
let result = deleteServerInformation()
if(result){
successLabel.hidden = false
successLabel.text = "Server Information Reset"
}
else {
errorLabel.hidden = false
errorLabel.text = "Failed to delete. Try again."
}
}
//Removes all server information stored in core data
func deleteServerInformation() -> Bool {
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext
let coord = appDel.persistentStoreCoordinator
let fetchRequest = NSFetchRequest(entityName: "Server")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try coord.executeRequest(deleteRequest, withContext: context)
return true
} catch let error as NSError {
debugPrint(error)
return false
}
}
//Clears old server information and commits new data to core data
func saveName(name: String, ip: String) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Server")
let entity = NSEntityDescription.entityForName("Server",
inManagedObjectContext:managedContext)
let server = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedContext)
server.setValue(name, forKey: "serverName")
server.setValue(ip, forKey: "serverIP")
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
let server = results as! [NSManagedObject]
if(server.count != 0){
deleteServerInformation()
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
//Call to switch view controller on successful submit
func switchToViewController(identifier: String) {
let viewController = self.storyboard!.instantiateViewControllerWithIdentifier(identifier)
self.navigationController?.pushViewController(viewController, animated: true)
}
}
I am new to swift so I imagine I am just missing some conceptual thing. I really don't have a good grasp on the core data stuff yet. From what I have read the view controller flow is all related to app delegate, so could it have to deal with how my deleteServerInfo is dealing with the app del AND my SaveServer also is dealing with it and when used one after another it causes issues? I'm sorry if I am way off, but it is the only thing I can think of that really changes between the two user interaction paths.
So basically the issue is the "submitServer" function runs fine and switches view over to userselect view controller when no other button is pushed in the view controller. However, if I press the button that triggers "resetServerInfo" first (which runs fine), when i click and run "submitServer" again it no longer switches view controllers.

Related

Is there a way to update an object in a core data model by pressing bar button item?

My goal here is to update an object in my core data by pressing the done button after editing the text.
The done button and the textfields below:
Here is some of my code,
#objc func doneTapped() {
do {
try context.save()
} catch {
print("Error saving the new information \(error)")
}
dateEditableTextF.resignFirstResponder()
selectedEventDate = dateEditableTextF.text
dateEditableTextF.isEnabled = false
costEditableTextF.resignFirstResponder()
selectedEventCost = costEditableTextF.text
costEditableTextF.isEnabled = false
gradesEditableTextF.resignFirstResponder()
selectedEventGrade = gradesEditableTextF.text
gradesEditableTextF.isEnabled = false
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped))
}
I expected that when I pressed the done button while running the app after editing the textfields, the information would update and that when I went back to the view controller, the information would be the same and my core data database would be update with an update attribute for that object.
What actually happened was when I finish editing the textfield, the data updates in the view controller, but when I leave the view controller and come back to it, the data reverts to the old entry.
I watched about 4 youtube videos of crud methods and they all were different scenarios and didn't match mine so I was hoping someone here could help. Thanks in advance.
Here's the rest of my view controller.
#IBOutlet weak var costEditableTextF: UITextField!
#IBOutlet weak var dateEditableTextF: UITextField!
#IBOutlet weak var gradesEditableTextF: UITextField!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var updateTheEvents = [Event]()
var selectedEventName: String?
var selectedEventDate: String?
var selectedEventCost: String?
var selectedEventGrade: String?
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = selectedEventName
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped))
if let dateToLoad = selectedEventDate {
dateEditableTextF.text = selectedEventDate
}
if let costToLoad = selectedEventCost {
costEditableTextF.text = selectedEventCost
}
if let gradesToLoad = selectedEventGrade {
gradesEditableTextF.text = selectedEventGrade
}
// Do any additional setup after loading the view.
}
#objc func editTapped() {
dateEditableTextF.becomeFirstResponder()
dateEditableTextF.isEnabled = true
costEditableTextF.isEnabled = true
gradesEditableTextF.isEnabled = true
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
}
First you need to create a storage to manage your persistentContainer and the CRUD operations:
class PersistenceManager {
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "your_xcdatamodeld_name") //Here you should type the name of your xcdatamodeld file without the extension .xcdatamodeld
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
return container
}()
}
Now to save data, you'll need a context. I strongly suggest that you use a global one. I had several issues accessing the store context from external functions (ie. stuff wasn't added/edited). Note that, despite it works great for me, I'm not sure wether a global context is the best practice. I have encountered any issues yet, however.
Inside of your PersistenceManager class, before the persistentContainer put the following code
static let shared = PersistenceManager()
var managedObjectContext: NSManagedObjectContext {
persistentContainer.viewContext
}
And, before and outside of the class put the following
let context = PersistenceManager.shared.managedObjectContext
...
class PersistenceManager { [...] }
Now you'll have to create your saving function like this:
func saveContext () {
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
This goes inside of the PersistenceManager class.
Now comes the fun part: You'll have to create the CRUD functions. These will all be inside of your PersistenceManager class. I'm going to show you a small demonstration about creating and editing entities.
Let's assume you have an entity named "Item" and it has the attributes name and price.
To save each item, you'll have a function like the following one:
func creaateNewItem(name: String, price: Int) -> Item {
let entity = NSEntityDescription.entity(forEntityName: Item, in: context)
let newItem = Item(entity: entity!, insertInto: context)
newItem.name = name
newItem.price = price
self.saveContext()
return newItem
}
To edit the item, you'll have to fetch it and then assign it the new values:
func editItem(currentItem: Item, newName: String, newPrice: Int) {
let currentName: String = currentItem.name! //Current name
//Looking for the item to edit
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
request.predicate = NSPredicate(format: "name = %#", currentName)
request.returnsObjectsAsFaults = false
do { //Editing the item
let editedItem = (try context.fetch(request))[0] as! Item
editedItem.name = newName
editedItem.price = newPrice
self.saveContext()
} catch let error {
print("Error \n \((error))")
}
}
As you see here I passed some parameters which will allow you to customise your Items. Obviously if you need to assign default values you can remove those parameters.
Now, in your view controller, you'll create an Item array object:
my item : [Item]?
Which will be filled with your items.
To edit your saved items by pressing a bar button you'll now simply have to do the following:
#objc func editMyItem(){
let newName = "Edited Item"
let newPrice = 15
PersistenceManager().editItem(currentItem: item[indexOfYourChoice], newName: newName, newPrice: newPrice)
}
And your item will be edited!
Note that if you want the text to come from a textfield the newPrice constant will be equal to that textfield's text, for instance.

Why tableView.reloadData() is not triggered after Core Data container.performBackgroundTask()

I am using Swift 4 to build a single view iOS 11 application that has a UITableViewController that is also defined as a delegate for a NSFetchedResultsController.
class MyTVC: UITableViewController, NSFetchedResultsControllerDeleagate {
var container:NSPersistentContainer? =
(UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
var frc : NSFetchedResultsController<Student>?
override func viewDidLoad() {
container?.performBackgroundTask { context in
// adds 100 dummy records in background
for i in 1...100 {
let student = Student(context: context)
student.name = "student \(i)"
}
try? context.save() // this works because count is printed below
if let count = try? context.count(for: Student.fetchRequest()) {
print("Number of students in core data: \(count)") // prints 100
}
} // end of background inserting.
// now defining frc:
if let context = container?.viewContext {
let request:NSFetchRequest<Student> = Student.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
frc = NSFetchedResultsController<Student> (
fetchRequest: request,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil )
try? frc?.performFetch() // this works and I get no errors
tableView.reloadData()
frc.delegate = self
} // end of frc definition
}
}
If I add one row of Student using the viewContext, the frc will fire the required methods to show it in the tableView. However, the 100 dummy rows are not shown. In fact, If I try to tell the tableview to reload after the insertion is done, my app starts to behave weirdly and becomes buggy, and does not do what it should do (i.e: does not delete rows, does not edit, etc).
But If I restart my app, without calling the dummy insertion, I can see the 100 rows inserted from the previous run.
The only problem is that I can't call tableView.reloadData() from the background thread, so I tried to do this:
// after printing the count, I did this:
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData() // causes UI to behave weirdly
}
then I tried to call viewContext.perform to reload the table view in the proper thread
func viewDidLoad() {
// code for inserting 100 dummy rows in background thread
// code for defining frc and setting self as delegate
if let context = container?.viewContext {
context.perform { [weak self] in
self?.tableView.reloadData() // that also causes UI to behave weirdly
}
}
}
How can tell my tableview to reload and display the 100 dummy rows in a thread-safe manner?
override func viewDidLoad() {
super.viewDidLoad()
//Always need your delegate for the UI to be set before calling the UI's delegate functions.
frc.delegate = self
//First we can grab any already stored values.
goFetch()
//This chunk just saves. I would consider putting it into a separate function such as "goSave()" and then call that from an event handler.
container?.performBackgroundTask { context in
//We are in a different queue than the main queue, hence "backgroundTask".
for i in 1...100 {
let student = Student(context: context)
student.name = "student \(i)"
}
try? context.save() // this works because count is printed below
if let count = try? context.count(for: Student.fetchRequest()) {
print("Number of students in core data: \(count)") // prints 100
}
//Now that we are done saving its ok to fetch again.
goFetch()
}
//goFetch(); Your other code was running here would start executing before the backgroundTask is done. bad idea.
//The reason it works if you restart the app because that data you didn't let finish saving is persisted
//So the second time Even though its saving another 100 in another queue there were still at least 100 records to fetch at time of fetch.
}
func goFetch() {
if let context = container?.viewContext {
let request:NSFetchRequest<Student> = Student.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
frc = NSFetchedResultsController<Student> (
fetchRequest: request,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil )
try? frc?.performFetch()
//Now that records are both stored and fetched its safe for our delegate to access the data on the main thread.
//To me it would make sense to do a tableView reload everytime data is fetched so I placed this inside o `goFetch()`
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
}
}
After a lot of reading about the NSFetchedResultsController and the NSPersistentContainer and finally finding an important piece of information here at SO I think I have a working example.
My code is slightly different since I used a project I had for this. Anyway here is what I did:
In my view controller I had a property for my container
private var persistentContainer = NSPersistentContainer(name: coreDataModelName)
And in viewDidLoad I loaded the persistent store and created my 100 records.
persistentContainer.loadPersistentStores { persistentStoreDescription, error in
if let error = error {
print("Unable to add Persistent Store [\(error)][\(error.localizedDescription)]")
} else {
self.createFakeNotes() // Here 100 elements get created
DispatchQueue.main.async {
self.setupView() // other stuff, not relevant
self.fetchNotes() // fetch using fetch result controller
self.tableView.reloadData()
}
}
}
Below is createFakeNotes() where I use a separate context for inserting the elements in a background thread, this code is pretty much taken from Apple's Core Data programming guide but to make the UI being updated I needed to set automaticallyMergesChangesFromParent to true which I found out in this SO answer
I also delete old notes first to make the testing easier.
private func createFakeNotes() {
let deleteRequest = NSBatchDeleteRequest(fetchRequest: Note.fetchRequest())
do {
try persistentContainer.persistentStoreCoordinator.execute(deleteRequest, with: persistentContainer.viewContext)
} catch {
print("Delete error [\(error)]")
return
}
let privateContext = persistentContainer.newBackgroundContext()
privateContext.automaticallyMergesChangesFromParent = true //Important!!!
privateContext.perform {
let createDate = Date()
for i in 1...100 {
let note = Note(context: privateContext)
note.title = String(format: "Title %2d", i)
note.contents = "Content"
note.createdAt = createDate
note.updatedAt = createDate
}
do {
try privateContext.save()
do {
try self.persistentContainer.viewContext.save()
} catch {
print("Fail saving main context [\(error.localizedDescription)")
}
} catch {
print("Fail saving private context [\(error.localizedDescription)")
}
}
}
You should fetch your data by calling it from viewwillappear and then try to reload your tableview.
override func viewWillAppear(_ animated: Bool) {
getdata()
tableView.reloadData()
}
func getdata() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do{
persons = try context.fetch(Person.fetchRequest())
}
catch {
print("fetching failed")
}
}

Swift - Core Data student info storage app errors

EDIT - i've played around with the code; still having issues.
i've been trying to modify the app in this tutorial so that i can enter student information and store it using core data. Ideally, i would like to be able to display that information on a label; but i haven't gotten that far yet. This is my first time working with core data and currently, i've hit a wall and need some assistance figuring out where in my code i've gone wrong and what to do to get it working.
So my questions are, how do i fix these errors.
and How would i got about displaying all the data after it's saved on a label.
Updated Screenshot
Updated Error Screenshot
Thanks in advance!
Code :
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet var name: UITextField!
#IBOutlet var address1: UITextField!
#IBOutlet var address2: UITextField!
#IBOutlet var city: UITextField!
#IBOutlet var state: UITextField!
#IBOutlet var zip: UITextField!
#IBOutlet var grade: UITextField!
#IBOutlet var status: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
#IBAction func insertStudent(_ sender: AnyObject) {
let context = getContext()
let entityDescription = NSEntityDescription.entity(forEntityName: "Contacts", in: context)
let contact = NSManagedObject(entity: entityDescription!, insertInto: context) as! Contacts
contact.student_name = name.text
contact.address1 = address1.text
contact.address2 = address2.text
contact.city = city.text
contact.grade = grade.text
contact.state = state.text
contact.zip = zip.text
var error: NSError?
//save the object
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Looks like you are trying to mix Swift versions. See code examples below and see if this helps clear up the issue.
AppDelegate
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "CDTest")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() 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.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() 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.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Functions to save and get data from CoreData in Swift 3.
func storeTranscription() {
let context = getContext()
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "ItemList", in: context)
let transc = NSManagedObject(entity: entity!, insertInto: context) as! ItemList
//set the entity values
transc.itemID = Double(itemid)
transc.productname = nametext
transc.amount = Double(amountDouble)
transc.stock = stockStatus
transc.inventoryDate = inventoryDate
//save the object
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func getTranscriptions () {
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<ItemList> = ItemList.fetchRequest()
do {
//go get the results
let searchResults = try getContext().fetch(fetchRequest)
fetchedStatsArray = searchResults as [NSManagedObject]
//I like to check the size of the returned results!
print ("num of results = \(searchResults.count)")
//You need to convert to NSManagedObject to use 'for' loops
for trans in searchResults as [NSManagedObject] {
//get the Key Value pairs (although there may be a better way to do that...
print("\(trans.value(forKey: "productname")!)")
let mdate = trans.value(forKey: "inventoryDate") as! Date
print(mdate)
}
} catch {
print("Error with request: \(error)")
}
}
Your Code converted Swift 3
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
#IBAction func insertStudent(_ sender: AnyObject) {
let context = getContext()
let entityDescription = NSEntityDescription.entity(forEntityName: "Contacts", in: context)
let contact = NSManagedObject(entity: entityDescription!, insertInto: context) as! Contacts
contact.student_name = name.text
contact.address1 = address1.text
contact.address2 = address2.text
contact.city = city.text
contact.grade = grade.text
contact.state = state.text
contact.zip = zip.text
var error: NSError?
//save the object
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}

How to reload TableView in other View?

I have some CoreData base wich I'm used in my TableView.
When I'm tried to clear those base in other View I have a message in my console log.
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)
for deleting CoreData Array I'm used this code
self.historyArray.removeAll()
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "History")
fetchRequest.returnsObjectsAsFaults = false
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
for managedObject in results
{
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
managedContext.deleteObject(managedObjectData)
}
} catch {
print("Detele all data")
}
I know I need to reload TableView, but how can I do this in other View?
ill tried this, but this code don't work.
var tableViewHistoryClass = HistoryView()
self.tableViewHistoryClass.tableView.reloadData()
Please help me to fix this message.
You can achieve this by using notification.
create observer in viewDidLoad method where you can display your table view data.
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"refreshTableView", name: "reloadTable", object: nil)
}
func refreshTableView () {
self.tableView.reloadData()
}
Second view controller
-> In this view controller you can change your data( if you want to do) or send data object
NSNotificationCenter.defaultCenter().postNotificationName("reloadTable", object: nil)
so like this it will reload your table view.
One solution is to notify your tableview when data is removed.
When data is removed your code post notifications :
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
for managedObject in results
{
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
managedContext.deleteObject(managedObjectData)
NSNotificationCenter
.defaultCenter()
.postNotificationName("dataDeleted", object: self)
}
}
And in controller where is your tableview add an observer for this notification:
override func viewDidLoad() {
NSNotificationCenter
.defaultCenter()
.addObserver(
self,
selector: #selector(viewController.reloadTableView),
name: "dataDeleted",
object: nil)
}
func reloadTableView() {
self.tableview.reloadData
}
Thanks all for answers!
I'm created new method, all my Clear CoreData function i added to my View in which i have TableView for showing all data from CoreData :P
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"clearCoreDataArray", name: "clearAllData", object: nil)
}
func clearCoreDataArray() {
historyArray.removeAll()
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "History")
fetchRequest.returnsObjectsAsFaults = false
do
{
let results = try managedContext.executeFetchRequest(fetchRequest)
for managedObject in results
{
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
managedContext.deleteObject(managedObjectData)
}
} catch {
print("Detele all data")
}
self.tableView.reloadData()
}
and in View when I'm need to use this method i use this code
NSNotificationCenter.defaultCenter().postNotificationName("clearAllData", object: self)
now i don't have any CoreData warnings

TableView.reloadData() doesn't work after save data into core data entity

I'm trying to insert a default record into my core data entity while the tableview first-time loaded and checked there's no data in the entity.
The data inserted just fine , but the reloadData() didn't work, after navigate to other view and navigate back to the view the data appears. no matter the reloadData() in or out of the .save() method.
override func viewDidLoad() {
let cateContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let categoryRequest = NSFetchRequest(entityName: "Category")
categoryArray = (try! cateContext.executeFetchRequest(categoryRequest)) as! [Category]
if categoryArray.count == 0 {
let category = NSEntityDescription.insertNewObjectForEntityForName("Category", inManagedObjectContext: cateContext) as! Category
category.sno = "1"
category.category = "General"
category.locate = false
do {
try cateContext.save()
self.categoryTableView.reloadData()
} catch let saveError as NSError {
print("Saving Error : \(saveError.localizedDescription)")
}
}
//self.categoryTableView.reloadData()
}
If your are calling self.categoryTableView.reloadData() in viewDidLoad() method it will not reload your tableView twice. You need to call self.categoryTableView.reloadData() after you have checked if entity existed again.