Swift multiple values being saved to coredata - ios

I'm making a game that has a few constants that are in it:
struct moneyConstants {
static var tapValue = NSInteger()
static var tapMultiplier = NSInteger()
static var moneyPerSecond = NSInteger()
static var money = NSInteger()
}
I'm using CoreData to save the values after when the application closes. I want to know if you are able to save multiple values at once. Lets say my code to save something is:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("Constants", inManagedObjectContext:managedContext)
let moneyS = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)
moneyS.setValue(moneyConstants.money, forKey: "moneySave")
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
If I wanted to save a second value like:
let moneyPerSecondS = NSManagedObject(entity:entity!, insertIntoManagedObjectContext:managedContext)
moneyPerSecondS.setValue(moneyConstants.moneyPerSecond, forKey: "money")
Can I place those lines before the do { section? Or do I have to put it after the do { section and then write another do { section?

Of course you can (if the attributes are declared in the model):
let moneyS = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)
moneyS.setValue(moneyConstants.money, forKey: "moneySave")
moneyS.setValue(moneyConstants.moneyPerSecond, forKey: "money")
Everything which does not throw is not required to be placed in a do scope.

Related

Why can't I set a variable on my custom class?

I'm creating my first iOS app in Swift, and I'm stuck on a basic thing. I want to create a custom class and set a variable. I keep seeing the error "Value of type [Item] has no member [name].
This is my custom class:
import UIKit
import Foundation
import CoreData
class Item:NSManagedObject {
var name:String?
convenience init(name: String?, insertIntoManagedObjectContext context: NSManagedObjectContext!) {
let entity = NSEntityDescription.entityForName("ItemEntity", inManagedObjectContext: context)!
self.init(entity: entity, insertIntoManagedObjectContext: context)
}
}
And this is my code that tries to use it:
func editItem(id:Int, category:String, brand:String, name:String, colour:String, purchasePrice:String, purchaseDate:String, expiryDate:String) -> Int {
// vars
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("ItemEntity", inManagedObjectContext: managedContext)
let item = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
var listItem = [Item]()
let fetchRequest = NSFetchRequest(entityName: "ItemEntity")
// fetch the item from the core data with the same ID
do{
let predicate = NSPredicate(format: "id == %#", String(id))
fetchRequest.predicate = predicate
fetchRequest.fetchLimit = 1
let results = try managedContext.executeFetchRequest(fetchRequest)
listItem = results as! [Item]
}
catch {
let fetchError = error as NSError
print (fetchError)
}
// edit the item
listItem.name = "text" // !! THIS IS THE LINE WHICH DISPLAYS THE ERROR
// save the item
do {
try managedContext.save()
}
catch {
let saveError = error as NSError
print (saveError)
}
}
Really appreciate your help, this one seems so basic but a lot of googling hasn't helped me figure it out.
listItem is an array of Item, so if you want to change the name of one thing in this list you should specify the index you wanna change, like
listItem[0].name = "text"
Put spaces around the colon. Syntax if I'm not mistaken.
I think the problem code is here:
let item = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext) as! Item
By default, the item type is NSManagedObject, so listItem have no member [name]. You need to cast down it to Item Object.

iOS - Data persist once into Core Data

I'm trying to save a bunch of data into core data. I could manage to save all the data into core data but it make no sense to have duplicate data inside core data because the function will be execute once on every build of the project. The approach that I am thinking now is empty the entity's record before I am adding new record to it. Just want to know is that got another way around to make sure that the data only persist once?
func persistCurrencyData() {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let currencyEntity = NSEntityDescription.entityForName("Currency", inManagedObjectContext: managedContext)
let countryEntity = NSEntityDescription.entityForName("Country", inManagedObjectContext: managedContext)
for currency in currencies {
let currencyObject = CurrencyCore(entity: currencyEntity!, insertIntoManagedObjectContext: managedContext)
currencyObject.setValue(currency.code, forKeyPath: "code")
currencyObject.setValue(currency.name, forKeyPath: "name")
for country in currency.country! {
let countryObject = CountryCore(entity: countryEntity!, insertIntoManagedObjectContext: managedContext)
countryObject.setValue(country.name, forKeyPath: "name")
countryObject.setValue(country.code, forKeyPath: "code")
countryObject.setValue(country.continent, forKeyPath: "continent")
countryObject.setValue(country.continentCode, forKeyPath: "continentCode")
countryObject.currency = currencyObject
}
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
Update:
Thanks to #Wain for giving me the idea. Basically what I done to solve the saving of duplicate data in core data is I included an GUID in my JSON file. Every time the code read the JSON file, it will save GUID into NSUserDefault and save data into core data. When it wants to read JSON file again in the next build, it will check whether the GUID is same as previous saved GUID. If it is different, the code will read the JSON file and repeat the process above. If not, it will proceed and ignore it.
func requestCurrenciesData() {
getCurrenciesDataFromFileWithSuccess { (data) -> Void in
var json: [String: AnyObject]
do {
json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! [String: AnyObject]
guard let currencyData = CurrencyData(json: json) else {
print("Error initializing object")
return
}
self.currencies = currencyData.currency!
// Checking the JSON's id is same as previous read
let defaults = NSUserDefaults.standardUserDefaults()
if let id = defaults.stringForKey("id")
{
if id == currencyData.id {
let notification = NSNotification(name: "CurrenciesDataUpdate", object: nil)
NSNotificationCenter.defaultCenter().postNotification(notification)
return
}
}
self.persistCurrencyDataForId(currencyData.id)
let notification = NSNotification(name: "CurrenciesDataUpdate", object: nil)
NSNotificationCenter.defaultCenter().postNotification(notification)
} catch {
print(error)
return
}
}
}
func persistCurrencyDataForId(id: String) {
// Save the new JSON's id into NSUserDefaults
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(id, forKey: "id")
// Delete all the records in existing table
deleteRecordsFromEntity("Country")
deleteRecordsFromEntity("Currency")
// Insert the new records
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let currencyEntity = NSEntityDescription.entityForName("Currency", inManagedObjectContext: managedContext)
let countryEntity = NSEntityDescription.entityForName("Country", inManagedObjectContext: managedContext)
for currency in currencies {
let currencyObject = CurrencyCore(entity: currencyEntity!, insertIntoManagedObjectContext: managedContext)
currencyObject.setValue(currency.code, forKeyPath: "code")
currencyObject.setValue(currency.name, forKeyPath: "name")
for country in currency.country! {
let countryObject = CountryCore(entity: countryEntity!, insertIntoManagedObjectContext: managedContext)
countryObject.setValue(country.name, forKeyPath: "name")
countryObject.setValue(country.code, forKeyPath: "code")
countryObject.setValue(country.continent, forKeyPath: "continent")
countryObject.setValue(country.continentCode, forKeyPath: "continentCode")
countryObject.currency = currencyObject
}
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
func deleteRecordsFromEntity(entityName: String) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let coordinator = appDelegate.persistentStoreCoordinator
let fetchRequest = NSFetchRequest(entityName: entityName)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try coordinator.executeRequest(deleteRequest, withContext: managedContext)
} catch let error as NSError {
print(error)
}
}
In general you can say 'if i have any currency entries in the data store, don't add more'. That could be done by adding a flag to use defaults or something like that when you do the first import, but a better option is to check the data store to see if it has any currency entries. To do this create a fetch request for currencyEntity and use countForFetchRequest:error: before you carry on with for currency in currencies {. If the count is greater than zero then you should return instead of processing the loop.
To be more efficient this check should actually be before you download and process the JSON...

Retrieve data from a one to many relationship core data

I need to retrieve the values of each attribute in a to many relationship. My code to load it is
func loadData() {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Company")
do {
//Get the results
let results = try managedContext.executeFetchRequest(fetchRequest)
//Load the results in the people array
people = results as! [NSManagedObject]
for i in 0..<people.count {
let data = people[i]
let variableToPrint = data.valueForKey("employee")
print(variableToPrint)
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
If I do that, it returns:
Optional(Relationship 'employee' fault on managed object
(0x7f93f363dd80) (entity: Company;
id: 0xd000000000080000
; data:
{
employee = "";
name = Apple; }))
My code to save to core data is
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let companyEntity = NSEntityDescription.entityForName("Company", inManagedObjectContext: managedContext)
let company = NSManagedObject(entity: companyEntity!, insertIntoManagedObjectContext: managedContext)
company.setValue("Apple", forKey: "name")
//Add employees
let employeeEntity = NSEntityDescription.entityForName("Employees", inManagedObjectContext: managedContext)
let person = NSManagedObject(entity: employeeEntity!, insertIntoManagedObjectContext: managedContext)
for i in 0..<employeeNameArray.count {
let name = employeeNameArray[i]
let when = dateJoinedArray[i]
let number = employeeNumberArray[i]
person.setValue(name, forKey: "employeeName")
person.setValue(number, forKey: "employeeNumber")
person.setValue(when, forKey: "dateHired")
company.setValue(NSSet(object: person), forKey: "employee")
}
//Employee info to company
company.setValue(NSSet(object: person), forKey: "employee")
do {
try managedContext.save()
//people.append(person)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
My core data setup has 2 entities. One called Company and one called Employees.
Company has a name attribute, and an employee relationship with a destination of Employees, and is to many.
In employees, I have `dateHired, employeeName, and employeeNumber attributes, and in relationships, I have a relationship called company with the destination Company, and is a to one type.
I need to be able to load all of the Employees attributes at the same time as the Company attributes as they are tied together.

Trouble Saving with CoreData and Swift 2.0

Problem
I'm trying to simply save a record and then fetch it but I think I'm doing something wrong here as my record isn't saving. The output window just shows an empty array.
I'm using the boiler-plate AppDelegate CoreData stack in Xcode 7 beta 5. [See Gist Here]
Attempt
Entity
Model
import Foundation
import CoreData
// #func(Person) edit: removed
class Person: NSManagedObject {
#NSManaged var firstName: String?
#NSManaged var lastName: String?
}
View Controller
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
seedPerson()
fetch()
}
func seedPerson() {
let managedContext = AppDelegate().managedObjectContext
let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedContext)
let person = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
// add our data
person.setValue("Dan", forKey: "firstName")
person.setValue("Beaulieu", forKey: "lastName")
// save it
do {
try AppDelegate().managedObjectContext.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
func fetch() {
let moc = AppDelegate().managedObjectContext
let personFetch = NSFetchRequest(entityName: "Person")
do {
let fetchedPerson = try moc.executeFetchRequest(personFetch) as! [Person]
print(fetchedPerson.first!.firstName)
} catch {
fatalError("Failed to fetch person: \(error)")
}
}
}
Desired Behavior
What I'm trying to return is my first name from the data store, however I don't think my record is ever saved which is why I'm getting is an empty array.
So my specific question is, how do I save using the boiler plate core data stack?
The problem was that I was creating a new instance of managedObjectContext and trying to save to it which obviously wouldn't work because I was working with the managed context that I created at the top of my method.
func seedPerson() {
let managedContext = AppDelegate().managedObjectContext
//let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedContext)
//let person = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
let person = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: managedContext)
// add our data
person.setValue("Dan", forKey: "firstName")
person.setValue("Beaulieu", forKey: "lastName")
// save it
do {
// this was the problem ///////////////
try managedContext.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
Video
I've uploaded a video tutorial on how to setup core data in swift 2 : https://www.youtube.com/watch?v=WcQkBYu86h8

Save data for tableview coredata in swift

I have passed two parameters from another tableview in order to save my notes "my Text" in different array. I just want to save myText for different row for the tableview but now i can just save and see the common myText.
var allnote = [NSManagedObject]()
var csname:Int = 1
var cspath:Int = 1
func saveNote(myText:String){
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedObjectContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Logitem", inManagedObjectContext: managedObjectContext)
let notes = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedObjectContext)
notes.setValue(myText, forKey: "itemText")
allnote.append(notes)
var error: NSError?
if managedObjectContext.save(&error) {
println("Couldn't save\(error?.userInfo)")
}
fetchnote()
}

Resources