K. Law
K. Law

Reputation: 2711

Problems linking objects in realm swift

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

Answers (3)

K. Law
K. Law

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

kishikawa katsumi
kishikawa katsumi

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

Austin
Austin

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

Related Questions