Using CoreData to save array containing dictionaries - ios

I'm trying to use CoreData framework inside an iOS app for the first time and I have some troubles with it.
I have a kind of complex type of array, containing tuples that contains dictionaries:
let DataSet: [( Float, Float, [String : String])] = ...
I created an NSManagedObjectContext and an NSManagedObject, I added the DataSet array to the NSManagedObject, but when I try to save the 1st NSManagedObjectContext, the app is crashing.
That's not happening using normal arrays but only with more complex ones like the one above.
Is there a way to deal with that problem? Do I need to adjust my xcdatamodel?
I would appreciate any help a lot.

First you need to declare 2 separate entities. One for Floats and another for Dictionary.
Then create "One to Many" relation ship between Float entity and Dictionary. It will look like this,
Then you need to convert your tuple into these 2 entities, Like this,
dataSet.forEach{ (member) in
let tuple = Test.(context: mainContext)
tuple.first = member.0
tuple.second = member.1
let dictionary = member.2
dictionary.forEach{ (key, value) in
let dick = Dick.(context: mainContext)
dick.key = key
dick.value = value
tuple.addToContains(dick)
}
}
Finally you need to save the values.
if mainContext.hasChanges {
do {
try mainContext.save()
} catch {
print(\(error))
}
}

Related

How to Make a Struct Version of the NSCountedSet Class?

I am developing an app in which I need to take two arrays, both holding the same custom data type, MenuItem.
I need to compare them and find the common elements of both arrays.
I compare the two arrays by converting them both to sets and then using the compare function of the set struct.
However, I then need to convert the array of common elements to a Counted Set so that I can find how many of each element exist in the group of common elements.
The problem I am having is with converting the the array of common elements to a Counted Set. In Swift, there is an NSCountedSet class but no CountedSet struct like there are for most built-in swift Data Types:
let groups = Array(self.menu.keys)
//menu and cart are dictionaries the structure [MenuGroup: [MenuItem]]
let cartGroups = Array(self.cart.keys)
let group = groups[indexPath.section]
if cartGroups.contains(group) {
let items = menu[group] as [MenuItem]!
let cartItems = cart[group]
let itemsSet = Set<MenuItem>(items!)
let cartItemsSet = Set<MenuItem>(cartItems!)
let similarSet = itemsSet.intersection(cartItemsSet)
let similarArray = NSMutableArray(Array(similarSet))
let similarCounterSet = NSCountedSet(array: similarArray)
}
I want to create a struct based off the NSCountedSet class so that I can convert the array of common elements to a counted set.
The if statement is for something else, it does not pertain to this question.
Any thoughts on how to do this? If anybody has a different approach to this problem feel free to mention that too.
Thanks,
Simon
Thanks to Martin R I Found An Example of How to do This:
There are various CountedSet implementation available, e.g. https://github.com/0x7fffffff/CountedSet.

iOS - Swift - Compare 2 entities for the values

I need to compare the values in one Entity another entity.
I donot want to have the one on one string comparison.
As it has so many Params, and the values will be keep adding in future.
Do we have any simple solution for this?
Its not about Core Data. Normal Custom Objects.
For Ex: I need to compare to Employee Object for its values.
func compareTwoEntities() -> Bool
{
let json = JSONSerializer.toJson(userEntity)
let json2 = JSONSerializer.toJson(userBackUpEntity)
if json == json2
{
return true
}
return false
}
You could try comparing two arrays made of these elements of entities. Have you tried that?

How to convert NSArray to Set?

Most of the posts here are on about how to convert a set into an array.But I would like to know if I could convert an array to a set.I have downloaded my array from parse and want to convert it to a set because I want the user to edit their details and the form builder I used needs to accept a set data type only.
This is what I got.The "Subjects" field is an NSArray in Parse.
let subjects = Set(currentuser?.objectForKey("Subjects"))
Basically the syntax is correct, but the compiler (and me too) doesn't know that the object for key Subjects is supposed to be an array. Use optional binding to check at least for an array of NSObject to conform to the requirement that the items in the array are hashable (thanks to dan for pointing that out):
if let userSubjects = currentuser?.objectForKey("Subjects") as? [NSObject] {
let subjects = Set(userSubjects)
}
If the real type of Subjects is more specific than [NSObject] use that instead

Extracting NSManagedObject attribute values from NSOrderedSet

I have an initializer that takes an array of Strings as a parameter. Rather than re-write the class and risk breaking things, I'd prefer to feed the initializer what it wants.
I'm trying to extract NSStrings from NSManagedObjects stored in an NSOrderedSet.
Here's what I've tried:
let soundsToPlay = sequenceToPlay.sounds as NSOrderedSet
for element in soundsToPlay {
// this prints out the object in console
print("\(element)")
// this, doesn't give me accessors for the sound object
// print("\(element.fileName)")
}
I'm missing something basic, but I'm not sure what. How would I enumerate the objects in an NSOrderedSet and extract the value of the attributes for the entities contained within the set?
I would suggest reading the documentation on KVC (Key Value Coding) as you can write this as one line of code:
let filenameArray = soundsToPlay.valueForKey("fileName").array()
The call to valueForKey will return an NSOrderedSet of the string and then you can convert that to an array with a call to array()
I figured it out. I was missing a step:
let soundsToPlay = sequenceToPlay.sounds as NSOrderedSet
for element in soundsToPlay {
// I have to tell the compiler what type of thing my thing is
let whatIWantToAccess = element as! MyObjectINeedAccessorsFor
print("\(whatIWantToAccess.fileName)")
}
Thats probably because compiler thinks that "element" is instance of NSManagedObject and it does not have fileName , try explicit type-casting , something like
for element: YourClass in soundsToPlay

Swift automatically creating temporary dictionaries

I'm working with a datasource for a UITableView where I need an array with dictionaries.
I tried making an array, and filling it with dictionaries in a for loop like this.
temporaryDataDict = [:]
temporaryDataDict = ["name":stockName, "ticker":ticker, "lastPrice":lastPrice, "purchasePrice":purchasePrice, "weight":weight, "daysHeld":daysHeld]
temporaryDataArray.append(temporaryDataDict)
But of course, when I start filling my tableView with the dataSource. I end up for 23 of the exact same dictionaries (the last one in the for loop).
This is of course, because it's changing the dictionary every time.
I havn't been able to find a way to keep the data in the dictionaries, or programatically make a new dictionary every time (since they need a new name otherwise it'll overwrite the data).
So how can I programatically make dictionaries everytime a for loop runs, then get the keys & values of these dictionaries?
or am I going about this completely wrong?
If it helps, here's the kind of data I'm working with.
I have a stock (or item) with 6 properties. So I think it makes the most sense to have an array where every item in the array is the "stock" as a dictionary that contains the 6 properties.
So is it possible to make swift automatically create these dictionaries for me? Since I don't know the amount of dictionaries needed.
PS.
I know this is what CoreData is for. I'm using these arrays and Dictionaries to later fill in my CoreData.
If the above isn't possible I am aware that I can probably create a new CoreData entity to accomplish what I want, but it doesn't seem like the best way to go about it.
Any help would be greatly appreciated! Thanks
I don't believe that a dictionary is the best sort of data structure to use in this case. Since typically a dictionary is composed of a unique key and a value.
I have edited this answer. Originally I suggested creating a class containing a property for each record field. Then I figured that this could be done using a tuple via a typealias for each record. Using a typealias gets around an issue related to creating arrays of tuples.
ETA: However please read the comments because Zaph who knows more about this than me reckons that using a Class is a stronger solution.
This is my tuple based solution. Most of what follows is just about quickly creating some dummy data:
typealias StockRecord = (stockName:String, ticker: String, lastPrice: Double, purchasePrice: Double, weight: Double, daysHeld: Int)
var temporaryDataArray = [StockRecord]()
// use a loop to create dummy records and add each to the array
// rough and ready - just to test the solution
var loopCounter: Int
for loopCounter = 0; loopCounter <= 23; loopCounter++ {
//some dummy field values for each record
var stockName = "stockName" + ("\(loopCounter)")
var ticker = "ticker" + ("\(loopCounter)")
var lastPrice = Double(loopCounter)
var purchasePrice = Double(loopCounter)
var weight = Double(loopCounter)
var daysHeld = loopCounter
var newRecord = (stockName, ticker, lastPrice, purchasePrice, weight, daysHeld)
temporaryDataArray.append(newRecord)
}
ETA: Iterate over the array - eg:
for recordEntry in temporaryDataArray {
var a = recordEntry.stockName
var b = recordEntry.ticker
// etc
}
Or with enumeration - eg:
for (count,recordEntry) in enumerate(temporaryDataArray) {
println("\(count) \(recordEntry)")
}
Output:
0 (stockName0, ticker0, 0.0, 0.0, 0.0, 0)
1 (stockName1, ticker1, 1.0, 1.0, 1.0, 1)
2 (stockName2, ticker2, 2.0, 2.0, 2.0, 2)
3 (stockName3, ticker3, 3.0, 3.0, 3.0, 3)
etc

Resources