Default value for a List in Realm - ios

I have a Realm model class as below.
class Trip: Object {
dynamic var userId: String = ""
dynamic var id: Int = 0
dynamic var startTimestamp: Int64 = 0
dynamic var endTimestamp: Int64 = 0
let bumpLocations = List<BumpLocation>()
let brakeLocations = List<BrakeLocation>()
dynamic var distance: Double = 0.0
dynamic var calories: Double = 0.0
dynamic var averageSpeed: Double = 0.0
}
I create objects of this like this.
let tripData: [String: Any] = [
"userId": self.trip!.userId,
"id": self.trip!.id,
"startTimestamp": self.trip!.startTimestamp,
"endTimestamp": self.trip!.endTimestamp,
"distance": self.trip!.distance,
"calories": self.trip!.calories,
"averageSpeed": self.trip!.averageSpeed
]
realm.create(Trip.self, value: tripData, update: true)
At the time of creating these objects, there are no values to be added to the properties bumpLocations and brakeLocations. So I need to add default values for these fields, right?
What's the default value for properties of type List?
I get a crash at realm.create. I think this is because the create function expects all the properties of the model class to be listed in the dictionary the same way as it is specified in the class. And since it's missing bumpLocations and brakeLocations, it messes up the order the class is created from the value dictionary? As in it adds the value of the distance field to the bumpLocations property and calories value to the brakeLocations property and so on.
The crash reports I got.
Report #1
Report 2
Got this output in the debug console.

No, you don't need to add a default values for the two lists, since they already have the default value of an empty List defined in your Realm object class definition.
In the line let bumpLocations = List<BumpLocation>() the parentheses create are the shorthand notation for calling an init method without any input arguments, so this line actually assigns an empty List to the bumpLocations variable.
class Trip: Object {
...
let bumpLocations = List<BumpLocation>()
let brakeLocations = List<BrakeLocation>()
}
Below code is perfectly valid.
let tripData: [String: Any] = [
"userId": self.trip!.userId,
"id": self.trip!.id,
"startTimestamp": self.trip!.startTimestamp,
"endTimestamp": self.trip!.endTimestamp,
"distance": self.trip!.distance,
"calories": self.trip!.calories,
"averageSpeed": self.trip!.averageSpeed,
]
try! realm.write {
realm.create(Trip.self, value: tripData)
}

Related

How would this JSON be represented with classes?

I have a JSON object that gets loaded as [String: Any]. I want to break down each part and turn the "Any" into an actual class. Here's one section of the JSON that I'm starting with:
"objects": {
"Yellow Fruits" = {
name = "Bananas";
numbers = (
0,
1
);
};
"Red Fruits" = {
name = "Strawberries";
numbers = (
2,
4,
5,
14,
15,
16,
17
);
};
}
I've tried representing these "fruits" with the following class:
class Fruit {
var name: String?
var officeIndicies: [Int]?
}
When I try to load this with
guard let fruits = json["objects"] as? [String: Fruit]
it seems that the Fruit class does not accurately represent what is in the json.
Is there something obvious I'm missing?

Adding 'Key:Value' in Multidimensional Dictionary is Overwriting

I declared and initialized a [[String:[String:String] dictionary. It's empty in the beginning, and I am trying to add multiple values under the parent keys.
var dictionary = [String:[String:String]
// some checks
dictionary[i] = ["name" : name]
dictionary[i] = ["from" : country]
dictionary[i] = ["age" : age]
When I do that, I end up having only age key as a child under [key: [String:String]. So it's overwriting when I use this approach.
What is the appropriate way of doing
Your code is creating a new dictionary on each line and assigning this in the dictionary for key i, so you end up with the last dictionary ["age" : age]
You need to create an inner dictionary, assign the values to this and then assign this to your outer dictionary;
var innerDict = [String:String]()
innerDict["name"] = name
innerDict["from"] = from
innerDict["age"] = age
dictionary[i] = innerDict
I would suggest, however, that you look at creating a Struct and put that in your outer dictionary rather than using a dictionary of dictionaries
func insert(key:String, value:String, at k:String) {
var d = dictionary[k] ?? [String:String]()
d[key] = value
dictionary[k] = d
}
And here's how to test it:
insert("name", value: name, at: i)
insert("from", value: country, at: i)
insert("age", value: age, at: i)
You can use optional chaining to assign to the inner dictionary, but you need to create the inner dictionary first.
// create the dictionary of dictionaries
var dictionary = [String:[String:String]]()
// some example constants to make your code work
let i = "abc"
let name = "Fred"
let country = "USA"
let age = "28"
// Use nil coalescing operator ?? to create
// dictionary[i] if it doesn't already exist
dictionary[i] = dictionary[i] ?? [:]
// Use optional chaining to assign to inner dictionary
dictionary[i]?["name"] = name
dictionary[i]?["from"] = country
dictionary[i]?["age"] = age
print(dictionary)
Output:
["abc": ["age": "28", "from": "USA", "name": "Fred"]]
Using these techniques, here's my version of #matt's insert(_:value:at:) function:
func insert(key:String, value:String, at k:String) {
dictionary[k] = dictionary[k] ?? [:]
dictionary[k]?[key] = value
}

How to append associative array elements in Swift

How do I create and append to an associative array in Swift? I would think it should be something like the following (note that some values are strings and others are numbers):
var myArray = []
var make = "chevy"
var year = 2008
var color = "red"
myArray.append("trackMake":make,"trackYear":year,"trackColor":color)
The goal is to be able to have an array full of results where I can make a call such as:
println(myArray[0]["trackMake"]) //and get chevy
println(myArray[0]["trackColor"]) //and get red
Simply like this:
myArray.append(["trackMake":make,"trackYear":year,"trackColor":color])
Add the brackets. This will make it a hash and append that to the array.
In such cases make (extensive) use of let:
let dict = ["trackMake":make,"trackYear":year,"trackColor":color]
myArray.append(dict)
The above assumes that your myArray has been declared as
var myArray = [[String:AnyObject]]()
so the compiler knows that it will take dictionary elements.
I accept above answer.It is good.Even you have given correct answer,I like to give simplest way.The following steps are useful,if you guys follow that.Also if someone new in swift and if they go through this,they can easily understand the steps.
STEP 1 : Declare and initialize the variables
var array = Array<AnyObject>()
var dict = Dictionary<String, AnyObject>()
var make = "chevy"
var year = 2008
var color = "red"
STEP 2 : Set the Dictionary(adding keys and Values)
dict["trackMake"] = make
dict["trackYear"] = year
dict["trackColor"] = color
println("the dict is-\(dict)")
STEP 3 : Append the Dictionary to Array
array.append(dict)
println("the array is-\(array)")
STEP 4 : Get Array values to variable(create the variable for getting value)
let getMakeValue = array[0]["trackMake"]
let getYearValue = array[0]["trackYear"]
let getColorValue = array[0]["trackColor"]
println("the getMakeValue is - \(getMakeValue)")
println("the getYearValue is - \(getYearValue)")
println("the getColorVlaue is - \(getColorValue)")
STEP 5: If you want to get values to string, do the following steps
var stringMakeValue:String = getMakeValue as String
var stringYearValue:String = ("\(getYearValue as Int)")
var stringColorValue:String = getColorValue as String
println("the stringMakeValue is - \(stringMakeValue)")
println("the stringYearValue is - \(stringYearValue)")
println("the stringColorValue is - \(stringColorValue)")
STEP 6 : Finally the total output values are
the dict is-[trackMake: chevy, trackColor: red, trackYear: 2008]
the array is-[{
trackColor = red;
trackMake = chevy;
trackYear = 2008;
}]
the getMakeValue is - Optional(chevy)
the getYearValue is - Optional(2008)
the getColorVlaue is - Optional(red)
the stringMakeValue is - chevy
the stringYearValue is - 2008
the stringColorValue is - red
Thank You
This sounds like you are wanting an array of objects that represent vehicles. You can either have an array of dictionaries or an array of vehicle objects.
Likely you will want to go with an object as Swift arrays and dictionaries must be typed. So your dictionary with string keys to values of differing types would end up having the type [String : Any] and you would be stuck casting back and forth. This would make your array of type [[String : Any ]].
Using an object you would just have an array of that type. Say your vehicle object's type is named Vehicle, that would make your array of type [Vehicle] and each array access would return an instance of that type.
If I want to try it with my own statement. Which also I want to extend my array with the data in my dictionary and print just the key from dictionary:
var myArray = ["Abdurrahman","Yomna"]
var myDic: [String: Any] = [
"ahmed": 23,
"amal": 33,
"fahdad": 88]
for index in 1...3 {
let dict: [String: Any] = [
"key": "new value"
]
// get existing items, or create new array if doesn't exist
var existingItems = myDic[myArray] as? [[String: Any]] ?? [[String: Any]]()
// append the item
existingItems.append(myArray)
// replace back into `data`
myDic[myArray] = existingItems
}

Swift shows nil value for Dictionary type

I have a dictionary of type < String, String>. It can access by index values like dictionary[0]. But i want to access each values in this in a simple way by using the key.
var rows: [Dictionary<String, String>] = []
rows = [..] // assigned some value
var value = rows[0]["id"]
println(rows[0]) // ["id": "2", "name": "Bob", "age": "19"]
println(value) // I get nil value
How can i access by this key format. Any suggestions. Thanks in advance.
I tried to read values from a CSV file. And assigned to rows. It works fine when i print rows[0] it shows the correct value. But on the next line if i print rows[0]["id"] it gives me a nil value. And i tried with manual dictionary like
rows = [["name": "alvin"]]
var value = rows[0]["name"]
println(value) // prints alvin
Whats the difference?
This could happen if your key has a space in it. Consider the following:
var rows: [Dictionary<String, String>] = []
rows = [["id ": "2", "name": "Bob", "age": "19"]] // assigned some value
var value = rows[0]["id"]
println(rows[0]) // ["id": "2", "name": "Bob", "age": "19"]
println(value) // I get nil value
To check your keys, print them out like this to see if there is any space in them:
for key in rows[0].keys {
println("XXX\(key)XXX")
}
prints:
XXXid XXX
XXXageXXX
XXXnameXXX
showing that key id is followed by a space, but age and name are not.

Create Dictionary<String, [SomeStruct]> from [SomeStruct] source-array

var sourceEntries: [Entry] = [entry1, ..., entry14]
var myDict: Dictionary<String, [Entry]> = [:]
for entry in sourceEntries {
if var array = myDict[entry.attribute1] { theArray.append(entry) }
else { myDict[entry.attribute1] = [entry] }
}
I am intending to create a Dictionary, which matches all the objects of the struct "Eintrag" with the same attribute from the source-Array "alleEinträge" to a String containing the value of the shared attribute. For some reason my final Dictionary just matches Arrays of one element to the Strings, although some Arrays ought to contain up to four elements.
The problem is that the array is passed by value (i.e. "copied"), so the array you are writing to when you say array.append is not the array that is "inside" the dictionary. You have to write back into the dictionary explicitly if you want to change what's in it.
Try it in a simple situation:
var dict = ["entry":[0,1,2]]
// your code
if var array = dict["entry"] { array.append(4) }
// so what happened?
println(dict) // [entry: [0, 1, 2]]
As you can see, the "4" never got into the dictionary.
You have to write back into the dictionary explicitly:
if var array = dict["entry"] { array.append(4); dict["entry"] = array }
FURTHER THOUGHTS: You got me thinking about whether there might be a more elegant way to do what you're trying to do. I'm not sure whether you will think this is "more elegant", but perhaps it has some appeal.
I will start by setting up a struct (like your Entry) with a name attribute:
struct Thing : Printable {
var name : String
var age : Int
var description : String {
return "{\(self.name), \(self.age)}"
}
}
Now I will create an array like your sourceEntries array, where some of the structs share the same name (like your shared attribute attribute1):
let t1 = Thing(name: "Jack", age: 40)
let t2 = Thing(name: "Jill", age: 38)
let t3 = Thing(name: "Jill", age: 37)
let arr = [t1,t2,t3]
And of course I will prepare the empty dictionary, like your myDict, which I call d:
var d = [String : [Thing]]()
Now I will create the dictionary! The idea is to use map and filter together to do all the work of creating key-value pairs, and then we just build the dictionary from those pairs:
let pairs : [(String, [Thing])] = arr.map {
t in (t.name, arr.filter{$0.name == t.name})
}
for pair in pairs { d[pair.0] = pair.1 }

Resources