0

In my iOS app, I get the following exception:

'Linking objects notifications are only supported on managed objects.'

when I try to add an observer block:

y.xxx.observe { ... }

to a property that is defined as such:

class Y: Object {
    ...
    let xxx = LinkingObjects(fromType: X.self, property: "y")
    ...
}

I believe this means that y.xxx does not have a Realm, and indeed I can see in the debugger that y.xxx.realm is nil. However, y.realm is NOT nil.

How can the linking objects not have a Realm if the object I am linking to does have one?

For completeness, this is how Class X is defined:

class X: Object {
    ...
    @Persisted var y: Y?
    ...
}

Realm version 10.11.0, RealmDatabase version 11.1.1.

Context: I am in the last phase of migrating an app that was originally written in ObjC to be purely in Swift. This means switching to the Swift version of Realm. I have not encountered this problem in the previous version of the app that is largely the same code base except that it uses a very old version of the Realm framework and the Realm objects are defined in ObjC.

Zsombor
  • 141
  • 7
  • Check out [this answer](https://stackoverflow.com/questions/67950349/understanding-linkingobjects-in-realm-xcode-12-also-when-to-use-it/67959807#67959807) for some additional info. – Jay Jul 29 '21 at 19:06
  • @Jay Thanks but I do not think that answer is applicable here. I believe I understand how linking objects are supposed to work, and it is exactly because of their automatic/computed nature that I fail to understand how a situation can arise where an object has a Realm but its linking objects do not. – Zsombor Jul 29 '21 at 22:41
  • I think I mis-read your post. You can do what you're asking so I provided an example as an answer. – Jay Jul 30 '21 at 20:28

2 Answers2

0

You can add an observer to a linking objects property as long as the objects are managed. Let me set this up starting with the PersonClass who has a List property of DogClass objects

class PersonClass: Object {
    @objc dynamic var _id = ObjectId.generate()
    @objc dynamic var name = "Jay"
    
    let dogList = List<DogClass>()

    override static func primaryKey() -> String? {
        return "_id"
    }
}

and then our DogClass has an inverse relationship to the PersonClass objects

class DogClass: Object {
    @objc dynamic var _id = ObjectId.generate()
    @objc dynamic var name = ""

    let linkingOwners = LinkingObjects(fromType: PersonClass.self, property: "dogList")

    override static func primaryKey() -> String? {
        return "_id"
    }
}

Then suppose we want to observe Spot's linkingOwners - both Jay and Cindy had Spot added to their dogList previously

let spot = realm.objects(DogClass.self).filter("name == 'Spot'").first!
self.peopleToken = spot.linkingOwners.observe { changes in
    switch changes {
    case .initial(let dogs):
        print("  spots owners have been loaded")

    case .update(_, let deletions, let insertions, let modifications ):
        print("  something changed in spots owners")

    case .error(let error):
        print(error.localizedDescription)
    }
}

Running this section of code outputs this to console and adds the observer the linkingObjects

  spots owners have been loaded

Then, lets make a change to one of the owners properties

    let jay = realm.objects(PersonClass.self).filter("name == 'Jay'").first!
    try! realm.write {
        jay.name = "Jay, Spots owner"
    }

that last piece of code will output this to the console

  something changed in spots owners

The above code creates a PersonClass object and a DogClass object object with a inverse relationship. The code then adds an observer the linkingObjects (PersonClass) and fires when one of them changes.

Jay
  • 34,438
  • 18
  • 52
  • 81
  • I appreciate the effort, but a) "@objc dynamic var" (and as it turns out, "LinkingObjects(fromType: ") is the old notation style, and b) even if this works, it doesn't answer my question as to why I was getting an exception. – Zsombor Aug 02 '21 at 21:28
0

Turns out the linking objects now have to be declared like so:

class Y: Object {
    ...
    @Persisted(originProperty: "y") var xxx: LinkingObjects<X>
    ...
}

I am not sure if the declaration style I used in my question is still supposed to be valid and if this is a bug, but using the new style gets rid of the exception.

Zsombor
  • 141
  • 7