Comments (4)
@bdkjones We've had ongoing issues with attempting to 'make it work'. Every time we went down that path, it ended up being intermittent and a bit wonky. The issues with linkingObjects becomes even bigger in a sync'ing situation as then it really fails.
Since the documentation states that functionality is not supported (it appears to work in some cases and then later it doesn't, especially with sync'ing), we decided to abandon the attempt as it may work now, "but not work on a later release", as was suggested to us by support a while back i.e. avoid doing that.
In reference to retain cycles, 100% agree! However, the objects here are not child objects - they are references to another object and are fully fledged objects on their own. Keep in mind the relationship is optional so if an object is deleted and deallocated for example, that reference goes to nil
If you run the debug memory graph on the code I provided, all of the objects play nicely - so far! :-)
We feel this functionality should exist and be supported so I strongly suggest asking for a feature request!
If you want to see what I mean, change your hard-coded observer to this
self.token = job.observe(keyPaths: ["parentProjects.parentClients.name"]) { [weak self] change in
Which should add an observer to watch for the parentClient name change. So then change the parent client name
try! realm.write {
parentClient!.name = "parent client changed name"
}
and see what is presented to the observer - no info that the clients name was changed even though that's the property being observed via the linking objects!
Property 'parentProjects' of object Job {
name = job name;
} changed to 'LinkingObjects<Project> <0x15af58150> (
[0] Project {
name = project name;
jobs = List<Job> <0x600002971ce0> (
[0] Job {
name = job name;
}
);
}
)'
change your observer to get the details of what changed like this
case .change(let object, let properties):
for property in properties {
print("Property '\(property.name)' of object \(object) changed to '\(property.newValue!)'")
}
I could be totally off-base here but that indicates it doesn't really work... Correctly. Which jibs with the docs.
from realm-swift.
@Jaycyn Makes sense. I hadn't seen that line in the docs previously and I haven't seen any failures with the string-based keyPaths, so I had no reason to suspect they weren't supported.
As for feature requests: that's a black hole of sadness and despair. There are requests more than 8 years old on here and every couple years someone asks for an update and...crickets. Asking Realm for features is like asking Apple for features: pointless.
from realm-swift.
While Realm objects are KVO compliant, linking objects are a bit different.
From the Realm Documentation on Key-Value Observation
You cannot observe LinkingObjects properties via Key-value observation.
Due to that limitation, we've implemented code to create our own relationships. While you give up some of the free stuff linking objects provides, manually handling that isn't a big deal. And it seems in your case you're not really using backlinks to multiple objects (many-many) as there is only ever one parent object.
What we do is to create the 1-many manually; here's three updated models
class Client: Object {
@Persisted var name: String
@Persisted var projects: RealmSwift.List<Project>
func addProject(withProject: Project) {
withProject.parentClient = self
self.projects.append(withProject)
}
}
class Project: Object {
@Persisted var name: String
@Persisted var parentClient: Client!
@Persisted var jobs: RealmSwift.List<Job>
func addJob(withJob: Job) {
withJob.parentProject = self
self.jobs.append(withJob)
}
}
class Job: Object {
@Persisted var name: String
@Persisted var parentProject: Project!
}
and then the observer which is about the same
self.token = job.observe(keyPaths: [\Job.name, \Job.parentProject.name, \Job.parentProject?.parentClient.name]) { [weak self] change in
switch change
{
case .change:
print("Change reached!") // Update UI here. DOES NOT FIRE for parentProject.parentClient.name changes.
default:
return // We don't care about initial state.
}
}
Then to populate
let client = Client()
let project = Project()
let job = Job()
client.name = "client name"
project.name = "project name"
job.name = "job name"
client.addProject(withProject: project)
project.addJob(withJob: job)
try! realm.write {
realm.add(client) //adds all objects to realm
}
Then when any name is updated
let job = realm.objects(Job.self).first!
let parentProj = job.parentProject
let parentClient = parentProj?.parentClient
try! realm.write {
job.name = "job changed name"
}
try! realm.write {
parentProj!.name = "parent proj changed name"
}
try! realm.write {
parentClient!.name = "parent client changed name"
}
the observer is called for each name change
Change reached!
Change reached!
Change reached!
from realm-swift.
@Jaycyn Sure, I see that approach. But there are two complications:
-
The LinkingObjects keyPaths DO work when they're specified as Strings rather than PartialKeyPaths. This implies that Realm can handle this.
-
Model objects where the parent has a strong reference to the child and the child has a strong reference to the parent are, in any other world, bad. It's a retain cycle. The only reason it works in Realm is that the properties are lazily-created on demand. A child object definitely shouldn't "own" its parent, though, and I'd like to avoid that anti pattern if at all possible.
from realm-swift.
Related Issues (20)
- Not all notifications did come. HOT 3
- undefined symbol while running realm 10.46.0 HOT 1
- macOS: Realm Environment Injection Crashes Preview HOT 6
- Crash when using RealmSwift with multiple modules (ver 10.49.1) HOT 1
- Issue with Nested Bundles and Disallowed Files When Archiving with Realm-Swift HOT 1
- Doesn't work with cocoapods HOT 3
- Add Sync tests for Collections in mixed HOT 1
- Code sign XCFramework HOT 1
- Realm 10.51.0 not available in SPM HOT 3
- Add append function to `@ObservedSectionedResults` HOT 1
- Crashing 100% when using @available(..., *) for a dynamic library in ObjC HOT 3
- Consider implementing a SwiftData Custom Store (new in iOS18) for Realm HOT 5
- Xcode 16: Write Blocks Risk Data Races Warnings HOT 6
- Update all uses of _unsafeInheritExecutor to use #isolation instead HOT 1
- Code sign our published xcframeworks HOT 1
- Update Binding for iOS 18's API changes HOT 1
- Switch to building RealmSwift in Swift 6 mode HOT 1
- Investigate explicitly built modules for RealmSwift HOT 1
- Add support for logging categories HOT 1
- After upgrading to 10.52.0 our app crashes on launch when we attempt to observe a collection HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from realm-swift.