I need to save my array to Core Data.
let array = [8, 17.7, 18, 21, 0, 0, 34]
The values inside that array, and the number of values are variable.
1. What do I declare inside my NSManagedObject class?
class PBOStatistics: NSManagedObject, Equatable {
#NSManaged var date: NSDate
#NSManaged var average: NSNumber
#NSManaged var historicAverage: NSNumber
#NSManaged var total: NSNumber
#NSManaged var historicTotal: NSNumber
#NSManaged var ordersCount: NSNumber
#NSManaged var historicOrdersCount: NSNumber
#NSManaged var values: [Double] //is it ok?
#NSManaged var location: PBOLocation
}
2. What do I declare inside my .xcdatamodel?
3. How do I save this in my Entity? (I use MagicalRecord)
let statistics = (PBOStatistics.MR_createInContext(context) as! PBOStatistics)
statistics.values = [8, 17.7, 18, 21, 0, 0, 34] //is it enough?
Ok, I made some research and testing. Using Transformable type, solution is simple:
1. What do I declare inside my NSManagedObject class?
#NSManaged var values: [NSNumber] //[Double] also works
2. What do I declare inside my .xcdatamodel?
Transformable data type.
3. How do I save this in my Entity?
statistics!.values = [23, 45, 567.8, 123, 0, 0] //just this
“You can store an NSArray or an NSDictionary as a transformable attribute. This will use the NSCoding to serialize the array or dictionary to an NSData attribute (and appropriately deserialize it upon access)” - Source
Or If you want to declare it as Binary Data then read this simple article:
Swift 3
As we don't have the implementation files anymore as of Swift 3, what we have to do is going to the xcdatamodeld file, select the entity and the desired attribute (in this example it is called values).
Set it as transformable and its custom class to [Double]. Now use it as a normal array.
Convert Array to NSData
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("Device",
inManagedObjectContext:managedContext)
let device = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedContext)
let data = NSKeyedArchiver.archivedDataWithRootObject(Array)
device.setValue(data, forKey: "dataOfArray")
do {
try managedContext.save()
devices.append(device)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
Convert NSData to Array
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Device")
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
if results.count != 0 {
for result in results {
let data = result.valueForKey("dataOfArray") as! NSData
let unarchiveObject = NSKeyedUnarchiver.unarchiveObjectWithData(data)
let arrayObject = unarchiveObject as AnyObject! as! [[String: String]]
Array = arrayObject
}
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
For Example : https://github.com/kkvinokk/Event-Tracker
If keeping it simple and store an array as a string
Try this:
// Array of Strings
let array: [String] = ["red", "green", "blue"]
let arrayAsString: String = array.description
let stringAsData = arrayAsString.data(using: String.Encoding.utf16)
let arrayBack: [String] = try! JSONDecoder().decode([String].self, from: stringAsData!)
For other data types respectively:
// Set of Doubles
let set: Set<Double> = [1, 2.0, 3]
let setAsString: String = set.description
let setStringAsData = setAsString.data(using: String.Encoding.utf16)
let setBack: Set<Double> = try! JSONDecoder().decode(Set<Double>.self, from: setStringAsData!)
Make entity attribute type as "Binary Data"
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:TheArray];
myEntity.arrayProperty = arrayData;
[self saveContext]; //Self if we are in the model class
Retrive original array as:
NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:anEntity.arrayProperty];
That's all.
Following code works for me to store array of JSON in CoreData
func saveLocation(model: [HomeModel],id: String){
let newUser = NSEntityDescription.insertNewObject(forEntityName: "HomeLocationModel", into: context)
do{
var dictArray = [[String: Any]]()
for i in 0..<model.count{
let dict = model[i].dictionaryRepresentation()
dictArray.append(dict)
}
let data = NSKeyedArchiver.archivedData(withRootObject: dictArray)
newUser.setValue(data, forKey: "locations")
newUser.setValue(id, forKey: "id")
try context.save()
}catch {
print("failure")
}
}
Related
There is a code containing description of Dictionary struct and receiving corresponding entries from Core Data
What string(s) should I insert before last bracket to cast NSArray to array of dictionaries?
struct Dictionary {
var name: String
var enableDirect: Bool
var enableReverse: Bool
init(name: String, enableDirect: Bool, enableReverse: Bool) {
self.name = name
self.enableDirect = enableDirect
self.enableReverse = enableReverse
}
}
func loadDictionariesFromStore() -> [Dictionary] {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Dictionaries")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)!
}
If you are sure that the NSArray is of type [Dictionary] you can make a forced downcast of results and return it:
return results as! [Dictionary]
// or directly return it
return context.executeFetchRequest(request, error: nil)! as! [Dictionary]
I use Swift. I can save data into a core data base. And I can even print out the data in a for loop but I can't load it into a table view. I have an empty string array(called subjects) that the table view uses it as a data source but I would like to load the data in a for loop into that array.
Here's how I save the data:
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var newSubject = NSEntityDescription.insertNewObjectForEntityForName("Subjects", inManagedObjectContext: context) as NSManagedObject
newSubject.setValue("" + classTextField.text, forKey: "subjectName")
context.save(nil)
Here's how I retrieve the data:
I have an empty string array in the class called subjects.
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Subjects")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)!
if(results.count > 0){
for res in results{
println(res)
subjects.append(res)
}
}else{
println("0 Results.")
}
So, I can print out the data as you can see in the for loop, but I can't add that res value into my subjects array which is used by the table view. But I get the AnyObject is not convertible to String error message.
Edit:
Sorry, I misunderstood the code.
You need to unwrap the results to an array of Subjects
if let resultsUnwrapped = results as? [Subjects] {
for res in resultsUnwrapped{
println(res.description())
subjects.append(res.subjectName)
}
}
It's the first time I'm trying to save and retrieve custom data to/from my core data, but I've run into an error saying:
fatal error: array cannot be bridged from Objective-C
when I try to load the data back.
My code looks like this, the arrayOfNames is declared as [String]:
#IBAction func saveTap(sender: AnyObject) {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let contxt: NSManagedObjectContext = appDel.managedObjectContext!
let en = NSEntityDescription.entityForName("Indexes", inManagedObjectContext: contxt)
let arrayData: NSData = NSKeyedArchiver.archivedDataWithRootObject(arrayOfNames)
let newIndex = Indexes(entity: en!, insertIntoManagedObjectContext: contxt)
newIndex.monday = arrayData
println(newIndex.monday)
contxt.save(nil)
}
#IBAction func loadTap(sender: AnyObject) {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let fetchReq = NSFetchRequest(entityName: "Indexes")
let en = NSEntityDescription.entityForName("Indexes", inManagedObjectContext: context)
var myList:[String] = context.executeFetchRequest(fetchReq, error: nil) as! [String]
println(myList)
}
My model-file looks like this:
#objc(Indexes)
class Indexes: NSManagedObject {
#NSManaged var monday: NSData
#NSManaged var tuesday: NSData
#NSManaged var wednesday: NSData
#NSManaged var thursday: NSData
#NSManaged var friday: NSData
}
I've also set all the attributes to transformable in my data model. As I said, it's the first time I'm doing this, so sorry if the solution is obvious.
Any suggestions would be appreciated.
executeFetchRequest returns [AnyObject]?, not [String], indeed the objects in the array should be Indexes instances which contain your archived arrays of strings.
So, you need to correct the array type that the results of the fetch are being placed into.
Core Data works great for the most part. When I click on name first VC (Items) and performSeque to the second VC (Costs), I can see the costsName and other data. But when I add second name in first VC I can see the same data as in first name.
I'm trying to make a one to many relationship.
I have 2 data models:
import Foundation
import CoreData
#objc(Items)
class Items: NSManagedObject {
#NSManaged var count: NSNumber
#NSManaged var name: String
#NSManaged var cost: NSSet
}
import Foundation
import CoreData
#objc(Costs)
class Costs: NSManagedObject {
#NSManaged var costsDate: NSDate
#NSManaged var costsName: String
#NSManaged var costsValue: NSNumber
#NSManaged var account: Items
}
Here is addAccount's (name of the first VC) save action:
#IBAction func saveButtonPressed(sender: UIBarButtonItem) {
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var managedObjectContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Items", inManagedObjectContext: managedObjectContext!)
let account = Items(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext!)
account.name = cellOneNameTextField.text
if cellTwoCountTextField.text.isEmpty {
} else {
account.count = (cellTwoCountTextField.text).toInt()!
}
// Saving data
appDelegate.saveContext()
var request = NSFetchRequest(entityName: "Items")
var error:NSError? = nil
var results:NSArray = managedObjectContext!.executeFetchRequest(request, error: &error)!
self.navigationController?.popViewControllerAnimated(true)
}
Here is addCost's save action:
#IBAction func saveButtonTapped(sender: UIBarButtonItem) {
// CoreData Access
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var managedObjectContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Costs", inManagedObjectContext: managedObjectContext!)
let cost = Costs(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext!)
cost.costsName = cellThreeNoteTextField.text
cost.costsValue = (cellOnePriceTextField.text).toInt()!
cost.costsDate = datePicker.date
// Saving data
appDelegate.saveContext()
var request = NSFetchRequest(entityName: "Costs")
var error:NSError? = nil
var results:NSArray = managedObjectContext!.executeFetchRequest(request, error: &error)!
for res in results {
println(res)
}
delegate?.refreshTable()
self.navigationController?.popViewControllerAnimated(true)
}
I don't know if you do it somewhere, but your Items should attach a Count object to itself using your cost variable from your Items. Something like :
let account = Items(...)
let cost = Cost(...)
account.cost.addObject(cost)//and changing your var cost:NSSet into var cost:NSMutableSet
//then save Items
(I haven't tried the addObject but you understand the principle)
My app parses podcast RSS feeds. I use 2 entities: Podcasts (to hold podcast-related data) and Episodes (Episodes data like summaries etc). After parsing a feed, I store the list of episodes in an Array called "episodesToDisplay". When a user subscribes to a podcast, I want to save the data held by that array in Core Data. Here is my code which throws an error on the annotated line below:
class Podcasts: UITableViewController {
var currentPodcast: Podcasts!
override func viewDidLoad() {
super.viewDidLoad()
let podcastsEntity = NSEntityDescription.entityForName("Podcasts", inManagedObjectContext: self.managedContext)
let podcastsFetch = NSFetchRequest(entityName: "Podcasts")
var error: NSError?
let result = self.managedContext.executeFetchRequest(podcastsFetch, error: &error) as [Podcasts]?
if let resu = result {
println("res is \(resu.count)")
self.currentPodcast = resu[0] as Podcasts
} else {
println("did not work")
}
}
#IBAction func subscribe(sender: AnyObject) {
for dict: AnyObject in episodesToDisplay {
let episodesEntity = NSEntityDescription.entityForName("Episodes", inManagedObjectContext: self.managedContext)
let episodesToSave = Episodes(entity: episodesEntity!, insertIntoManagedObjectContext: self.managedContext)
var episodes = currentPodcast.episode.mutableCopy() as NSMutableOrderedSet
let btDict = dict as NSDictionary <---------------- Crash
episodesToSave.title = btDict["title"] as String
episodesToSave.summary = btDict["summary"] as String
episodesToSave.link = btDict["link"] as String
episodes.addObject(episodesToSave)
currentPodcast.episode = episodes.copy() as NSOrderedSet
}
// Save
var error:NSError?
if !self.managedContext.save(&error) {
println("could not save \(error)")
}
}
Any ideas please?
The error indicates that your array doesn't contain NSDictionary objects - that is why you get dynamic cast exception when you try and access an element as an NSDictionary.
From your comment it seems that your array actually contains MWFeedItem objects, so all you need to do is change your code to use that object type and then you can access the properties of the MWFeedItem -
#IBAction func subscribe(sender: AnyObject) {
for item: MWFeedItem in episodesToDisplay {
let episodesEntity = NSEntityDescription.entityForName("Episodes", inManagedObjectContext: self.managedContext)
let episodesToSave = Episodes(entity: episodesEntity!, insertIntoManagedObjectContext: self.managedContext)
var episodes = currentPodcast.episode.mutableCopy() as NSMutableOrderedSet
episodesToSave.title = item.title
episodesToSave.summary = item.summary
episodesToSave.link = item.link
episodes.addObject(episodesToSave)
currentPodcast.episode = episodes.copy() as NSOrderedSet
}