I am programming an iOS app using Swift, following a tutorial on Youtube. The app will have the same function as a to-do-list-app, but another use. However, when I expect the data to be saved (and printed in the debugger) nothing happens. Have I done something wrong?
#IBAction func saveTapped(sender: AnyObject) {
println("SaveTapped")
// Reference to our app delegate
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
// Reference moc
let contxt: NSManagedObjectContext = appDel.managedObjectContext!
let en = NSEntityDescription.entityForName("Tankningslista", inManagedObjectContext: contxt)
// Create instance of our data model and initialize
var nyTankning = Model(entity: en!, insertIntoManagedObjectContext: contxt)
// Map our properties
nyTankning.liter = (textFieldLiter.text as NSString).floatValue
nyTankning.kronor = (textFieldKronor.text as NSString).floatValue
nyTankning.literpris = (textFieldLiterpris.text as NSString).floatValue
//nyTankning.datum = datePickerDatum.date
// Save our context
contxt.save(nil)
println(nyTankning) //HERE I ESPECT THE DATA TO BE PRINTED IN THE DEBUG WINDOW
// navigate back to root vc
self.navigationController?.popToRootViewControllerAnimated(true)
}
You need to fetch the data first in order to display. Now you only save it. See my additions in your code after saving the data.
#IBAction func saveTapped(sender: AnyObject) {
println("SaveTapped")
// Reference to our app delegate
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
// Reference moc
let contxt: NSManagedObjectContext = appDel.managedObjectContext!
let en = NSEntityDescription.entityForName("Tankningslista",inIntoManagedObjectContext: contxt)
// Create instance of our data model and initialize
// Use your NSManagedModel to initialize not only the Model Keyword!
var nyTankning = Tankningslista(entity: en!, insertIntoManagedObjectContext: contxt)
// Map our properties
nyTankning.liter = (textFieldLiter.text as NSString).floatValue
nyTankning.kronor = (textFieldKronor.text as NSString).floatValue
nyTankning.literpris = (textFieldLiterpris.text as NSString).floatValue
//nyTankning.datum = datePickerDatum.date
// Save our context
if contxt.save(nil) {
// Fetch the Data from Core Data first....
let fetchRequest = NSfetchRequest(entityName: "Tankningslista")
var error:NSError?
var result = contxt.executeFetchRequest(fetchRequest, error: &error) as [Tankningslista]
for res in result {
// Now you can display the data
println(res.liter)
......
......
}
// End of the fetching
} else {
println(error)
}
//println(nyTankning) //HERE I ESPECT THE DATA TO BE PRINTED IN THE DEBUG WINDOW
// navigate back to root vc
self.navigationController?.popToRootViewControllerAnimated(true)
I hope that solution will solve your problem.
Puuh, there is a lot to improve, I really suggest you take a "real" iOS/ swift course on a platform like Udemy/ Bitfountain or Udacity. First, you need to fetch the ManagedObject somewhere either in a function (then store the results in an array) or with NSFetchedResultController (which is mostly used for CoreData with TableViews) then I am not sure what you have in your numberOfRowsInSection function, here you should also have the correct return values. As I said, to fix that here is really too much...
Related
I'm trying to synch the core data between more than one ViewController. I have an attribute called Score, which is in my Core Data model. In the first ViewController:
// Defining context
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
The following code is inside this first ViewController:
// Creating a new username & Saving it to Core Data
let newUser = UserInfo(context: self.context)
newUser.name = usersName.text
newUser.birthday = bdPicker.date
newUser.gender = genderTextField.text!
newUser.prevTested = yesOrNoTextField.text!
newUser.score = 0
// Core Data calling method
saveInfo()
func saveInfo(){
do {
try self.context.save()
} catch {
print("Error saving context\(error)")
}
}
In the remaining ViewControllers, I want to access the Score attribute and modify it. Now, how is it possible to access all Score attribute from all the remaining controllers in my app.
OverView
I continue to run into issues with adding multiple values to my Core Data entity. All i need to do is simply add 6 string-value items from a text field into Core Data. Specific examples/critique of my code would be very appreciated, as i am nearing mental break down with this issue.
The Issue
The first time i ran this, i tested it by saving only the first line (the product name) to core data and then printing it off. It worked perfect. After that, i tried the same method for all of them, and then tried printing. My program would set a breakpoint next to the "entity1.setValue(three, forKey: "serialNo")."
I also get a message in the debugger area that says (lldb).
If i try to step through the breakpoint, everything just prints out as 'nil'.
CODE
#IBAction func saveButton(sender: AnyObject) {
let appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
let entity1 = NSEntityDescription.insertNewObjectForEntityForName("UsedInfo", inManagedObjectContext:context) as NSManagedObject
let one = pickerTextField.text
let two = modelName.text
let three = serialNo.text
let four = YOM.text
let five = engineHours.text
let six = locationOfMachine.text
entity1.setValue(one, forKey: "product")
entity1.setValue(two, forKey:"modelName")
entity1.setValue(three, forKey:"serialNo")
entity1.setValue(four, forKey:"yom")
entity1.setValue(five, forKey:"engineHours")
entity1.setValue(six, forKey:"location")
print(entity1.valueForKey("product"))
print(entity1.valueForKey("modelName"))
print(entity1.valueForKey("serialNo"))
print(entity1.valueForKey("yom"))
print(entity1.valueForKey("engineHours"))
do {
try context.save()
}
catch {
print("error")
}
}
I am trying to create a Today Extension Widget which displays stored data in the widget.
Here's what I have done;
Added New Today Widget Target
Set up UIViewController for widget
Enable App Groups for both the app and extension
Now I have hit a road block, I am unsure the best way to retrieve and display a simple array of fetched data.
There is very little Swift tutorials and they often do not use core data.
In the main app project I fetch the array.
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let request = NSFetchRequest(entityName: "Objects")
do {
try
self.objectsArray = moc.executeFetchRequest(request) as! [Objects]
} catch {
}
How can I use NSUserDefaults to store the objects array and then use in the today widget extension ? Or Even an array of string values.
1) Get url to your database
var containerPath: String = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier‌​(YOUR_SECURITY_APP_GROUP).path
var sqlitePath: String = "(containerPath)/("database.sqlite")"
2) Create Persistent Store Coordinator as you do in parent app.
3) Set it for your Managed Object context
context = NSManagedObjectContext()
context.persistentStoreCoordinator = coordinator
4) Retrieve objects as you do in your parent app
let moc = context
let request = NSFetchRequest(entityName: "Objects")
do {
try self.objectsArray = moc.executeFetchRequest(request) as! [Objects]
} catch {}
If you set up the App Groups correct and added the same group for both Application and Extension you can use NSUserDefaults. Just for instance, to write something from the app, you need:
static func setSharedScoreNumber(score: Int) {
let defaults = UserDefaults(suiteName: "group.bubblewrapSharedDefaults") // this is the name of the group we added in "App Groups"
defaults?.set(String(score), forKey: "score")
defaults?.synchronize()
}
And to read from Todays Extension:
private func getScore() -> String {
let defaults = UserDefaults(suiteName: "group.bubblewrapSharedDefaults")
defaults?.synchronize()
return String(describing: defaults!.object(forKey: "score") ?? "0")
}
Here's the complete guide how to do so.
as in the title, I want to delete data from the CoreData when the user logs out from his account
What I wrote is this:
let moc = DataController().managedObjectContext
var context : NSManagedObjectContext?
var entityCurrentValue : NSEntityDescription?
var entityPreviousValue : NSEntityDescription?
var entityLastAccess : NSEntityDescription?
override func viewDidLoad() {
super.viewDidLoad()
loadCoreData()
}
}
func loadCoreData(){
context = moc
entityCurrentValue = NSEntityDescription.entityForName("CurrentValue", inManagedObjectContext: context!)
entityPreviousValue = NSEntityDescription.entityForName("PreviousValue", inManagedObjectContext: context!)
entityLastAccess = NSEntityDescription.entityForName("LastAccess", inManagedObjectContext: context!)
}
#IBAction func logoutButton_clicked(Sender: UIButton!) {
PFUser.logOut()
deleteElement(entityCurrentValue!)
deleteElement(entityPreviousValue!)
deleteElement(entityLastAccess!)
self.performSegueWithIdentifier("loginSegue", sender: Sender)
}
in this function i try to delete elements from the entity
func deleteElement(entity : NSEntityDescription){
let fetchRequest = NSFetchRequest()
fetchRequest.entity = entity
fetchRequest.fetchBatchSize = 50
var fetchResult = Array<AnyObject>()
do{
try fetchResult = (context?.executeFetchRequest(fetchRequest))!
}catch{
fatalError()
}
for entity in fetchResult as! [NSManagedObject] {
self.context?.deleteObject(entity)
}
}
The problem is that when i log out, and than I log in with another account, the app loads data that are already stored into the memory. Can someone help me? Thanks
A managed object context is only a virtual representation of the data on disk. So when you delete an object from a managed object context, it is not deleted from disk but simply marked as deleted inside the context.
In order to persist the changes of you context on disk, you need to save the context after performing the delete operations, which is what is missing from your code.
I'd like to update a CoreData Object.
Backgrund: I made an app which includes a UITableView. In the textLabel of the UITableViewCell is a name. In the detailTextLabel of this cell is a date which can be changed/updated. Now I'd like to change this date.
I wrote the following code:
var people = [NSManagedObject]()
func saveDate(date: NSDate) {
//1
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext:managedContext)
let person = people[dateIndexPath.row]
//3
person.setValue(date, forKey: "datum")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
//5
people.append(person)
tableView.reloadData()
}
Now, if I run this code:
The date is successfully updated but the cell in which the date has been updated is displayed 2 times. For example if I added 3 cells and changed the date in the 3rd cell, I now get 4 cells displayed and 2 of them have the same content/are duplicated.
Does someone knows how to solve this problem?
You're adding an additional object to your array each time. Your updated Person is already in the array and will display the new information when you reload your table data. To fix this, just take out this line:
people.append(person)
You're going to want to associate some kind of unique identifier attribute to your Person class. This allows to retrieve that same object later using it identifier. I would suggest using a UUID string value, called personID, identifier, or something similar.
You can override the awakeFromInsert method on your Person class like so:
// This is called when a new Person is inserted into a context
override func awakeFromInsert()
{
super.awakeFromInsert()
// Automatically assign a randomly-generated UUID
self.identifier = NSUUID().UUIDString
}
When you want to edit an existing Person, you want to retrieve it by the UUID. I suggest a class function like so (in the Person class):
class func personWithIdentifier(identifier: String, inContext context: NSManagedObjectContext) -> Person?
{
let fetchRequest = NSFetchRequest(entityName: "Person")
fetchRequest.predicate = NSPredicate(format: "identifier ==[c] %#", identifier)
fetchRequest.fetchLimit = 1 // Only want the first result
var error : NSError?
let results = context.executeFetchRequest(fetchRequest, error: &error) as [Person]
// Handle error here
return results.first?
}
This way you can use the following function:
let identifier = ...
let context = ...
var person = Person.personWithIdentifier(identifier, inContext: context)
if let person = person
{
// Edit the person
person.value = // change the values as you need
}
else
{
// Person does not exist!
person = // possibly create a person?
}