Binding an Ordered Relationship with an NSArrayController
Asked Answered
V

2

11

How does one bind an NSArrayController's content to the entities in an ordered to-many relationship?

I have an unordered to-many relationship in my Core Data model, and an NSArrayController whose Content Set is bound to that relationship from the parent entity. This works fine, the data is accessible from the NSArrayController, no problem.

I decided during development that it would be better to allow users to manually reorder these child objects, so I changed the relationship to an ordered one. Now, when my NSArrayController is being created from my nib, the following error is presented:

Cannot create NSSet from object Relationship '...' fault on managed object ... of class _NSFaultingMutableOrderedSet

Now actually, I think this all makes sense: It's an ordered relationship, so now I'm getting an ordered set. Binding it to Content Array also would be inappropriate, since it's now an NSOrderedSet, not an array. My question is: Now how do I bind this relationship's data back into the NSArrayController?

Vachell answered 25/2, 2013 at 23:39 Comment(2)
I came across this problem too and I am pretty convinced this is a bug with NSArrayController - filed a bug report.Rhizoid
It seems, based on the workaround cited in Hal's answer, that really no one has a "true" way to bind it. I'll make a bug report as well, because IMO it should be a showstopper, workaround or not.Vachell
G
9

The fundamental problem is that a Core Data ordered to-many relationship returns an NSOrderedSet, and NSOrderedSet is not a subclass of NSSet. Any array controller bindings that expect an NSSet will fail.

Tom Fewster has a detailed blog post describing the use of NSValueTransformer to work around this shortcoming, converting between NSOrderedSet and NSArray on the fly. He also provides a sample implementation on Github.

Gusti answered 24/3, 2013 at 23:55 Comment(2)
Thanks! As I point out in the last paragraph of the question, I'm aware that the inheritance from NSSet (rather, the lack thereof) is the problem with the bindings as things currently stand. But this value transformer approach is a life saver! I'll be sure to take a look at it.Vachell
The problem with the workaround (I think) is that the mutable accessors won't be used, which means that any change means reassigning/reconverting the entire set.Rhizoid
W
11

I came across this discussion while searching to see if there've been any new developments on this front. In a shipping app I currently bind the array controller's content array to orderedSetKey.@array and it works just fine, not sure if I discovered that myself or if someone else suggested it somewhere.

Walden answered 21/10, 2013 at 1:25 Comment(2)
I am not sure this is THE solution, because the "array" operator calls on NSOrderSet's "array" method, which returns a "facade" array object, which is immutable by design - (see its header-file doc in NSOrderSet.h). This means, the NSArrayController can "bind" but will fail to make any changes to the NSOrderedSet. This is no more than half-way-binding. read-only solution.Banquette
quite true indeed. If you need mutability, this will fail. Good catch;)Zirconium
G
9

The fundamental problem is that a Core Data ordered to-many relationship returns an NSOrderedSet, and NSOrderedSet is not a subclass of NSSet. Any array controller bindings that expect an NSSet will fail.

Tom Fewster has a detailed blog post describing the use of NSValueTransformer to work around this shortcoming, converting between NSOrderedSet and NSArray on the fly. He also provides a sample implementation on Github.

Gusti answered 24/3, 2013 at 23:55 Comment(2)
Thanks! As I point out in the last paragraph of the question, I'm aware that the inheritance from NSSet (rather, the lack thereof) is the problem with the bindings as things currently stand. But this value transformer approach is a life saver! I'll be sure to take a look at it.Vachell
The problem with the workaround (I think) is that the mutable accessors won't be used, which means that any change means reassigning/reconverting the entire set.Rhizoid

© 2022 - 2024 — McMap. All rights reserved.