Reputation: 2711
I am having problems linking objects in realm. I read the question and answer titled "Nested objects in realm" and tried the answer suggested but it did not work for me.
Here are my object classes:
import Foundation
import RealmSwift
class Job: Object {
dynamic var id = NSUUID().UUIDString
dynamic var name = ""
dynamic var address = ""
dynamic var phone = ""
dynamic var email = ""
dynamic var notes = ""
dynamic var material = 0.0
dynamic var edge = 0.0
dynamic var splash = 0.0
dynamic var discount = 0.0
dynamic var trip = 0.0
let rooms = List<Room>()
override static func primaryKey() -> String {
return "id"
}
}
import Foundation
import RealmSwift
class Room: Object {
dynamic var id = NSUUID().UUIDString
dynamic var name = ""
dynamic var material = 0.0
dynamic var edge = 0.0
dynamic var splash = 0.0
dynamic var sinkType = ""
dynamic var sinkModel = ""
dynamic var numberOfSinks = 0
dynamic var faucet = ""
dynamic var rangeType = ""
dynamic var notes = ""
dynamic var jobs: Job?
let countertops = List<Countertop>()
//var linksToJob: [Job] {
// return linkingObjects(Job.self, forProperty: "rooms")
//}
override static func primaryKey() -> String {
return "id"
}
}
import Foundation
import RealmSwift
class Countertop: Object {
dynamic var id = NSUUID().UUIDString
dynamic var depth = 0.0
dynamic var width = 0.0
dynamic var cabDescription = ""
dynamic var sqFt = 0.0
dynamic var room: Room?
//var linkToRoom: [Room] {
// return linkingObjects(Room.self, forProperty: "countertops")
//}
override static func primaryKey() -> String {
return "id"
}
}
Here are the functions I use to save the data:
@IBAction func saveButton() {
jobs.name = nameTF.text!
jobs.address = addressTF.text!
jobs.phone = phoneTF.text!
jobs.email = emailTF.text!
jobs.notes = notesTV.text!
jobs.discount = Double(discountTF.text!)!
jobs.material = Double(materialTF.text!)!
jobs.edge = Double(edgeTF.text!)!
jobs.splash = Double(splashTF.text!)!
jobs.trip = Double(tripTF.text!)!
do {
try! realm.write {
realm.add(jobs)
}
}
print(jobs)
// print(Realm.Configuration.defaultConfiguration.path!)
}
func saveData(){
rooms.name = nameTF.text!
rooms.material = Double(materialTF.text!)!
rooms.edge = Double(edgeTF.text!)!
rooms.splash = Double(splashTF.text!)!
rooms.notes = notesTV.text
rooms.sinkType = sinkTypeTF.text!
rooms.sinkModel = sinkModelTF.text!
rooms.numberOfSinks = Int(numberSinksTF.text!)!
rooms.faucet = faucetTF.text!
rooms.rangeType = rangeTF.text!
rooms.jobs?.id = keyValueLabel.text!
//rooms.linksToJob
do {
try! realm.write {
realm.add(rooms)
}
}
print(rooms)
}
and:
@IBAction func addNextButton(sender: AnyObject) {
// self.realm.beginWrite()
let realm = try! Realm()
if widthTF.text != "" {
Calculations.depth = Double(depthTF.text!)!
Calculations.width = Double(widthTF.text!)!
let depthAdded = depthTF.text
cabinetDepth.append(Double(depthAdded!)!)
let widthAdded = widthTF.text
cabinetWidth.append(Double(widthAdded!)!)
let descriptionAdded = pickerLabel.text
cabinetDescription.append(descriptionAdded!)
let runningTotal = Calculations.squareFeet()
squareFeetToBeAdded.append(runningTotal)
let sum = squareFeetToBeAdded.reduce(0,combine: {$0 + $1})
let roundedSqFt = Double(round(sum * 10) / 10)
sqFtLabel.text = "\(roundedSqFt)"
countertops.depth = Double(depthTF.text!)!
countertops.width = Double(widthTF.text!)!
countertops.cabDescription = pickerLabel.text!
countertops.sqFt = Double(sqFtLabel.text!)!
//countertops.linkToRoom
do {
try realm.write {
realm.add(countertops)
}
print(countertops)
} catch {
print("an error occurred")
}
widthTF.text = ""
numberTable.reloadData()
widthTF.becomeFirstResponder()
}
}
When I save the data and print the results here is what I get:
Job {
id = 00F95F55-54D8-426E-B483-C990A4171002;
name = Ken;
address = Address;
phone = phone;
email = email;
notes = Notes :;
material = 8;
edge = 0;
splash = 4;
discount = 1;
trip = 0;
rooms = RLMArray <0x7ffef9df29c0> (
);
}
Room {
id = 7D3F86B9-FCD7-4CB7-AD6E-9B8141A7390C;
name = Kitchen;
material = 9;
edge = 0;
splash = 4;
sinkType = Undermount Kitchen;
sinkModel = 50/50 Stainless Steel;
numberOfSinks = 1;
faucet = Single Hole;
rangeType = Free Standing Range;
notes = Notes:;
jobs = (null);
countertops = RLMArray <0x7ffef9df3720> (
);
}
Countertop {
id = 992B8BAE-392F-4513-85DC-CBA191D2AE08;
depth = 25.5;
width = 65;
cabDescription = Cabinet;
sqFt = 11.5;
room = (null);
}
As you can see the links return null. Please tell me what I am doing wrong here. Note: I comment out the linkingObjects in the models because it caused a crash. I'm not sure why.
Upvotes: 2
Views: 4677
Reputation: 2711
Thanks to Austin who got me on the right track. Here is the code that finally did it.
@IBAction func roomSaveNextBtnPushed(_ sender: UIButton) {
let room = Room()
room.roomName = roomTF.text!
room.material = materialTF.text!
room.edge = edgeTF.text!
room.job = realm.objects(Job.self).last
try! realm.write {
realm.add(room)
print(room)
}
}
The link is made in the ' realm.object(Job.self).last ' line of code. This adds a room to a job as expected.
The suggestion in Austin's example ' let room = realm.create(Room.self) ' caused an error, and the project would not compile.
I am using Xcode 8 with Swift 3 and Realm-swift 1.1.0
Thanks again to those who offered help.
Upvotes: 0
Reputation: 10573
Because you add each objects into the Realm individually without linking. If you'd like to link the objects, you should add the objects to the List
properties, such like rooms
and countertops
. Also for to-one relationships, you should assign the object to the property.
So you need write the code something like the following:
...
rooms.faucet = faucetTF.text!
rooms.rangeType = rangeTF.text!
...
rooms.countertops.append(countertops)
...
jobs.rooms.append(rooms)
And,
...
countertops.rooms = rooms
...
rooms.jobs = jobs
For more details, see also the documents:
Upvotes: 0
Reputation: 1437
You should use references to existing realm objects when adding them. So rather than this:
func saveData(){
rooms.name = nameTF.text!
rooms.material = Double(materialTF.text!)!
rooms.edge = Double(edgeTF.text!)!
rooms.splash = Double(splashTF.text!)!
rooms.notes = notesTV.text
rooms.sinkType = sinkTypeTF.text!
rooms.sinkModel = sinkModelTF.text!
rooms.numberOfSinks = Int(numberSinksTF.text!)!
rooms.faucet = faucetTF.text!
rooms.rangeType = rangeTF.text!
rooms.jobs?.id = keyValueLabel.text!
//rooms.linksToJob
do {
try! realm.write {
realm.add(rooms)
}
}
print(rooms)
}
You would use something like this:
let realm = try! Realm()
let room = realm.create(Room.self)
room.name = nameTF.text!
room.material = Double(materialTF.text!)!
...
let job = realm.create(Job.self)
job.name = "My job name"
...
room.job = job
Since it looks like you're entering these on separate screens, you will add a room, then you want to add a job:
if let existingJob = realm.objects(Job).filter("name == '\(jobNameToLookup)'").first {
room.job = existingJob
}
For a list, just do room.countertops.append(newCountetop), where newCountertop is the result of realm.create
Upvotes: 1