Trying to create a Swift Realm Data Model - ios

I have looked at the Realm.io docs. I am working on an application to track my vehicle expenses. I have put together what I think might work for a data model in Realm, but I am new to it and not sure if this is something that will work or if there is a better way to do it. Here is what I have, and I have not put this in a project and tried to compile yet. The realm.io docs are a little vague to me, so maybe someone can tell me what you think. I have included some comments in places that I am just not sure how to achieve what I'm going for...
// Vehicle model
class Vehicle : RLMObject {
dynamic var name = “”
dynamic var number = “”
dynamic var currentMiles = 0
dynamic var entries = RLMArray(objectClassName: Entry.className())
}
// Entry model
class Entry: RLMObject {
dynamic var vehicle: Vehicle //??
dynamic var date = NSDate()
dynamic var expense = 0.0
dynamic var mileage : Vehicle.currentMiles // want to update the Vehicle mileage with each entry
}
// Gas model
class Gas: Entry {
dynamic var gallons = 0
dynamic var pricePerGallon = 0.0
}
// OilChange model
class OilChange : Entry {
dynamic var milesBetweenChanges = 0
}
// Other Service model
class OtherService: Entry {
dynamic var notes = “”
}

You're on the right track! The only model that needs work is Entry, I think. First, here's your model with my annotations:
// Entry model
class Entry: RLMObject {
dynamic var vehicle: Vehicle // This is valid Swift, but you'll need to set the value in the designated initializer (`init()`).
dynamic var date = NSDate()
dynamic var expense = 0.0
dynamic var mileage : Vehicle.currentMiles // This isn't valid Swift, since `Vehicle` is a class, and doesn't have a `currentMiles` member
}
What you want is something like this:
// Entry model
class Entry: RLMObject {
dynamic var vehicle = Vehicle() // Use a default value so that `init()` succeeds, but you can still use `init(vehicle: Vehicle)` in your code
dynamic var date = NSDate()
dynamic var expense = 0.0
dynamic var mileage = 0
init() {
// Must override init() when adding a convenience initializer
super.init()
}
convenience init(vehicle: Vehicle) {
super.init()
self.vehicle = vehicle
mileage = vehicle.currentMiles
}
}
It's unfortunate that you find Realm's docs vague. Please let us know if there's anything in particular you'd like us to clarify. We're a pretty approachable bunch!

Related

Why I can't change value in nested Models?

I have 2 class , First class has a property which inheritance from second class
class FirstModel{
var firstType : Secondmodel?
}
class Secondmodel{
var secondType : Int?
}
Now I want to set a value to secondType so I code
var Modelll = FirstModel()
Modelll.firstType?.secondType = 100
When I try to read this property with print(Modelll.firstType?.secondType) it return nil
So first question is why I couldn't read this
But I try to do this
var Modelll = FirstModel()
var ModelSecond = Secondmodel()
ModelSecond.secondType = 100
Modelll.firstType = ModelSecond
print(Modelll.firstType?.secondType)
It works perfectly , printed out Optional(100) I really dont understand whats going on behind the scene. Can anyone explain this?
First of all, all variables and constant should be named with lowercased symbol. With Uppercased only names of classes, structs, protocols, enums etc
You problem is that when You init FirstModel, firstType variable is nil by default
var model = FirstModel()
print(model.firstType) //prints nil
so You need to do
var model = FirstModel()
model.firstType = SecondModel() //use camel case in naming
model.firstType?.secondType = 100
print(model.firstType?.secondType) // prints 100
Ammm.. Because you don't initiate firstType with an instance in your first try.
You can add something like this
class FirstModel{
var firstType : Secondmodel?
init() {
self.firstType = Secondmodel()
}
}
But this is not exactly how things should be done. Here is not a problem of nesting, you just don't give a value in firstyType property.
The best case should be like:
class Secondmodel{
var secondType : Int?
init(secondType: Int) {
self.secondType = secondType
}
}
var modelll = FirstModel()
modelll.firstType = SecondModel(secondType: 100)
You should read more about OOP.
..and objects should not be named with capital letters

Realm how to save item if not exist else it should update

I have a data coming from webservice. I have same models made in my project. To demonstrate the model let me show a little idea of my model
Model1:
class Standard {
var Id = 0
var standardName = ""
var students : [StudentModel] = nil
}
Model2:
class StudentModel {
var Id = 0
var stdName = ""
var Teacher: [TeacherModel] = nil
}
Model3:
class TeacherModel {
var Id = 0
var Name = ""
}
Now what I am facing is as follow :
I have TeacherModel in DB already, but I dont have student model and standard model instance int he Realm, so it is supposed to save coming student and standard data in Realm. and skip or update TeacherModel in Realm. But right now it is crashing on TeachModel data as one Teacher with same things are already saved in Realm.SO i am looking forward to some sort of method in which it update or just skip saving Item if already exist in the Realm.
Note: These models are just to demonstrate my case, where as I know there are many typos and other thing. Also I did not showed any implementation of Realm over my Models. Its just to show you the things to make you understand.
Well you need to have class func primaryKey() -> String? overriden.
override class func primaryKey() -> String? {
return "Id"
}
And then use realm.write(...) or realm.create(...) functions with update parameter set to true.

How to link two Realm objects

I'm new to iOS development and currently using Realm as database. My first tableview display Restaurant object and second table display customer objects. How can i link this two objects?. Means when i click each restaurant it will display different customer.
class Restaurant: Object {
dynamic var restname: String = ""
dynamic var date: String = ""
}
class Customer: Object {
dynamic var id = 0
dynamic var name: String = ""
dynamic var price: Float = 0.0
dynamic var drinks: Float = 0.0
override static func primaryKey() -> String? {
return "id"
}
}
You make references to your models like so
class Customer: Object {
dynamic var restaurant: Restaurant?
}
You also have the possibility to get reverse relationship with LinkingObjects(fromType:, property:)
You can write in your other model
class Restaurant: Object {
let customers = LinkingObjects(fromType: Customer.self, property: "restaurant")
}
That way you don't duplicate relationships.
If I understand, in Restaurant class put this:
dynamic var _customer = Optional(Customer())
or in Customer class put this line:
dynamic var _restaurant = Optional(Restaurant())
NOTE: Name of variable with lower dash, may be any name, my habit is to put lower dash

Realm iOS relationship from mysql json results

I want to use Realm to my iOS app but I have a problem with the relationship. What I want to achieve is a relationship between the following two RLMobjects :
class Catalogue: RLMObject {
dynamic var ID = ""
dynamic var greekName = ""
dynamic var deutschName = ""
dynamic var createdAt = NSDate()
dynamic var updatedAt = NSDate()
override class func primaryKey() -> String? {
return "ID"
}
}
class Products: RLMObject {
dynamic var foodName = ""
dynamic var foodDescription = ""
dynamic var foodPrice = ""
dynamic var createdAt = NSDate()
dynamic var updatedAt = NSDate()
dynamic var category: Catalogue?
}
I am retrieving all my data from a server in JSON format and the problem is that
I can not set the category as relationship to Catalogue ID.
In my database the category field is a foreign key to the Catalogue ID.
Does anyone knows how can I do that in Realm?
Thank you in advance.
Rather than storing the Catalogue ID in the dynamic var category: Catalogue? relationship field you will need to find the Catalogue object and just store that directly. This is how you link objects and is an important and powerful part of using NoSQL type DB's like Realm.
I would also add an array of products relationship on Catalogue so that you can link all the products to the Catalogue itself.
You can see more discussion about this here if that wasn't fully clear. Hope this helps

Classes and calling the properties Dynamically, Swift

I have two swift classes with two fairly similar properties (I have made the ones below the same for the purpose of this question) I want to use. I want to call the properties dynamically in the ViewDidLoad and I have used an array as shown below so I can change the index and choose which class to call. Unfortunately I get the error
Anyobject does not have a member named speciesType
What could I have missed or am I approaching the whole problem in the wrong way?
class Lion {
var age = 45
var speciesType = "Felidae"
}
class Lioness {
var age = 10
var speciesType = "Panthera"
}
var animal1 = Lion()
var animal2 = Lioness()
var animalKingDom = [animal1, animal2]
var colourChanging = animalKingDom[0].speciesType
Why dont you create a protocol that extracts out the common properties from both the classes.
class Lion {
var age = 45
var speciesType = "Felidae"
}
class Lioness {
var age = 10
var speciesType = "Panthera"
}
protocol LionType {
var speciesType: String { get set }
var age: Int { get set }
}
extension Lion: LionType { }
extension Lioness: LionType { }
var animal1 = Lion()
var animal2 = Lioness()
var animalKingDom: [LionType] = [animal1, animal2]
var colourChanging = animalKingDom[0].speciesType
I created a protocol LionType and added extension to both the classes to conform to the protocol. Since both the classes already have age and speciesType, the classes will remain unchanged. And finally, a small modification to your animalKingDom array could make it work easily.
By the way, I added a protocol LionType, I think it makes more sense to name it AnimalType which fits for all animals not just lions :)
I prefer the syntax where you declare the protocol before the classes, and let the classes explicit implement the protocol upon creation.
import Cocoa
protocol Animal {
var age: Int { get set }
var speciesType: String { get set }
}
class Lion: Animal {
var age: Int
var speciesType: String
init(age: Int, speciesType: String) {
self.age = age
self.speciesType = speciesType
}
}
class Lioness: Animal {
var age: Int
var speciesType: String
init(age: Int, speciesType: String) {
self.age = age
self.speciesType = speciesType
}
}
var l1 = Lion(age: 5, speciesType: "Cat")
var l2 = Lioness(age: 6, speciesType: "Doge")
var animalArray: [Animal] = [l1, l2]
for animal in animalArray {
print(animal.age)
print(animal.speciesType)
}
Also I'm not sure I would give a class for both male and female of an animal. But it totally depends on your business domain.
The compiler infer that the generic type of your array is 'AnyObject'.
Try removing one element from your array, and the compiler will find the good type of your array.
The compiler is not able to know that Lion and Lioness has a property in common.
You can either make a superclass or a protocol like GeneratorOne suggests.
I think that what you really want to do is have two instances of a single class (or better yet, if your real example is anything like this one, a struct). Let's keep using your Lion class. Two instances would then be
var lion = Lion()
lion.age = 45
lion.family = "Felidae"
var lioness = Lion()
lioness.age = 10
lioness.family = "Panthera"
(I'm ignoring the fact that your male and female are in different families. :))

Resources