I am working on my first project with CoreData and I have the data model setup.
I have a tableview with an Add button that triggers an alert and lets the user enter a string:
func handleAdd() {
let alert = UIAlertController(title: "New Company", message: "Add a new company", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) {
[unowned self] action in
guard let textField = alert.textFields?.first,
let newCompany = textField.text else {
return
}
self.save(name: newCompany)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
The string is added to an NSManagedObject array:
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
// 1
let managedContext =
appDelegate.persistentContainer.viewContext
// 2
let entity =
NSEntityDescription.entity(forEntityName: "Company",
in: managedContext)!
let company = NSManagedObject(entity: entity,
insertInto: managedContext)
// 3
company.setValue(name, forKeyPath: "name")
// 4
do {
try managedContext.save()
companies.append(company)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
All looking good so far except I want the app to launch with 5 cells already in place, then let the user add/delete as they wish. How do I set the 5 defaults that I want the app to launch with? I tried adding the below code to viewWillAppear
let entity =
NSEntityDescription.entity(forEntityName: "Company",
in: managedContext)!
let company = NSManagedObject(entity: entity,
insertInto: managedContext)
company.setValue("Apple", forKeyPath: "name")
company.setValue("Google", forKeyPath: "name")
company.setValue("Facebook", forKeyPath: "name")
company.setValue("Tesla", forKeyPath: "name")
company.setValue("Twitter", forKeyPath: "name")
self.save(name: "Apple")
self.save(name: "Google")
self.save(name: "Facebook")
self.save(name: "Tesla")
self.save(name: "Twitter")
At load time they all appear. Then when I navigate off the page and come back, they are added again. I know this is because they are in viewWillAppear and get called every time the page loads.
Apple's docs (Core Data Programming Guide) are a bit hard to swallow as a beginner but they do say
For small datasets, create the managed objects directly in code.
If you are using iOS or creating an application for OS X that is not document-based, you can add a check on application launch to determine whether a file exists at the location you specify for the application’s store. If it doesn't, you need to import the data.
I believe that second snippet is what I'm looking for in my case (correct me if I'm wrong), however I'm not sure how to implement it, so any help on how to set these defaults so they are added once (on load) and only once would be much appreciated!
Here are the initializers if they are of interest
var companies = [NSManagedObject]()
var container: NSPersistentContainer!
let managedContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let companyEntity = "Company"
EDIT: code added to app delegate
let vc = ViewController()
let entity = NSEntityDescription.entity(forEntityName: "Company", in: managedContext)!
let company = NSManagedObject(entity: entity,insertInto: managedContext)
let userDefaults = UserDefaults.standard
userDefaults.set(true, forKey: "firstRun")
if userDefaults.valueForKey("firstRun") == true {
company.setValue("Apple", forKeyPath: "name")
company.setValue("Google", forKeyPath: "name")
company.setValue("Facebook", forKeyPath: "name")
company.setValue("Tesla", forKeyPath: "name")
company.setValue("Twitter", forKeyPath: "name")
vc.save(name: "Apple")
vc.save(name: "Google")
vc.save(name: "Facebook")
vc.save(name: "Tesla")
vc.save(name: "Twitter")
userDefaults.set(false, forKey: "firstRun")
}
According to my comment and your – obviously failing – code after EDIT this is a suggestion how to implement firstRun:
First register the default value in applicationDidFinishLaunching, the lines are necessary even if the default value has been changed meanwhile.
let userDefaults = UserDefaults.standard
let defaultValues = ["firstRun" : true]
userDefaults.register(defaults: defaultValues)
Then check the value (UserDefaults has a bool(forKey function) and create the companies. It's crucial that the code to register default values is executed before using the values.
if userDefaults.bool(forKey: "firstRun") {
let defaultCompanies = ["Apple", "Google", "Facebook", "Tesla", "Twitter"]
let entity = NSEntityDescription.entity(forEntityName: "Company", in: managedContext)!
for companyName in defaultCompanies {
let company = NSManagedObject(entity: entity,insertInto: managedContext)
company.setValue(companyName, forKey: "name") // not keyPath
companies.append(company)
}
do {
try managedContext.save()
userDefaults.set(false, forKey: "firstRun")
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
In your code you are creating one company and change the name value 5 times without saving this particular company. Practically that code does nothing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With