我目前在我的项目中有2个视图:一个ViewController
,带有一个显示事务列表的TableView和一个ViewController
,用于创建新事务。
我遇到的问题是,在创建新事务后,它会成功加载到我的TableView上,但是当我强制关闭并重新打开应用程序时,该值是重复的。据我所知,save()
函数仅被调用一次,AppDelegate / SceneDelegate中没有任何反应。请参阅GIF以获取正在发生的事的示例。
这是我的TranasctionsTableViewController:
class TransactionsTableViewController: UIViewController {
// MARK: - Properties
var entries: [NSManagedObject] = []
var container: NSPersistentContainer!
// MARK: - IBOutlets
@IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// setup persistent container
container = NSPersistentContainer(name: "expenses")
// load store
container.loadPersistentStores { storeDescription, error in
if let error = error {
print("Unresolved error \(error)")
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier! {
case "NewTransactionSegue":
// pass an entry to the destination segue
let destination = segue.destination as! UINavigationController
let targetController = destination.topViewController as! NewTransactionViewController
let managedContext = container.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Entry", in: managedContext)!
let entry = NSManagedObject(entity: entity, insertInto: managedContext)
targetController.entry = entry as? Entry
default:
print("Unknown segue: \(segue.identifier!)")
}
}
@IBAction func unwindToTransactionList(sender: UIStoryboardSegue) {
print("unwind segue called!")
if let sourceViewController = sender.source as? NewTransactionViewController, let entry = sourceViewController.entry {
print(entry)
self.save(entryDescription: entry.entryDescription, amount: entry.amount, date: entry.date, id: entry.id)
// reset the tableView to defaults if no data message was displayed before loading data.
if self.tableView.backgroundView != nil {
self.tableView.backgroundView = nil
self.tableView.separatorStyle = .singleLine
}
self.tableView.reloadData()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// load managedCOntext
let managedContext = container.viewContext
// try to fetch data from CoreData. If successful, load into entries.
do {
entries = try managedContext.fetch(Entry.fetchRequest())
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
// save a new entry to the data store
func save(entryDescription: String, amount: Double, date: Date, id: UUID) {
print("save called!!")
let managedContext = container.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Entry", in: managedContext)!
let entry = NSManagedObject(entity: entity, insertInto: managedContext)
entry.setValue(entryDescription, forKey: "entryDescription")
entry.setValue(amount, forKey: "amount")
entry.setValue(date, forKey: "date")
entry.setValue(id, forKey: "id")
do {
try managedContext.save()
entries.append(entry)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
// save the current container context
func saveContext() {
if container.viewContext.hasChanges {
do {
try container.viewContext.save()
} catch {
print("An error occurred while saving: \(error)")
}
}
}
}
这是我的NewTransactionViewController:
class NewTransactionViewController: UIViewController, UITextFieldDelegate {
/*
This value is either passed by `TransactionTableViewController` in `prepare(for:sender:)`
or constructed as part of adding a new transaction.
*/
var entry: Entry?
// MARK: - IBOutlets
@IBOutlet weak var transactionDescriptionLabel: UILabel!
@IBOutlet var transactionDescriptionTextField: UITextField!
@IBOutlet var transactionAmountLabel: UILabel!
@IBOutlet var transactionAmountTextField: UITextField!
@IBOutlet weak var cancelButton: UIBarButtonItem!
@IBOutlet weak var saveButton: UIBarButtonItem!
// MARK: Constants
let TRANSACTION_DESCRIPTION_TEXT_FIELD_TAG = 0
let TRANSACTION_AMOUNT_TEXT_FIELD_TAG = 1
override func viewDidLoad() {
super.viewDidLoad()
// Handle textfield input through delegate callbacks.
transactionDescriptionTextField.delegate = self
transactionAmountTextField.delegate = self
// Adds done button to keypad
transactionAmountTextField.addDoneButtonToKeyboard(myAction: #selector(self.transactionAmountTextField.resignFirstResponder))
}
// MARK: - UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// If the First Responder is the Description Text Field, transfer First Responder to Amount Text Field
if (textField.tag == TRANSACTION_DESCRIPTION_TEXT_FIELD_TAG) {
transactionAmountTextField.becomeFirstResponder()
}
textField.resignFirstResponder()
return true
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: segue)
// Configure the destination view controller only when the save button is pressed.
guard let button = sender as? UIBarButtonItem, button === saveButton else {
os_log("The save button was not pressed, cancelling", log: OSLog.default, type: .debug)
return
}
let transactionDescription = transactionDescriptionTextField.text ?? ""
let transactionAmount = Double(transactionAmountTextField.text!) ?? 0.00
// Set the entry to be passed to TransactionTableViewController after the unwind segue.
entry?.setValue(transactionDescription, forKey: "entryDescription")
entry?.setValue(transactionAmount, forKey: "amount")
entry?.setValue(UUID(), forKey: "id")
entry?.setValue(Date(), forKey: "date")
}
// MARK: - IBActions
@IBAction func cancelButtonTapped(sender: UIBarButtonItem) {
}
@IBAction func saveButtonTapped(sender: UIBarButtonItem) {
}
}