Data-swift/ManagedModels

Can we support Swift arrays (`[]`) for toMany properties?

helje5 opened this issue · 5 comments

This would be nice to have:

@Model class Groups: NSManagedObject {
  var items : [ Item ]
}

Related to issue #1.

Maybe there is some hackish solution which swizzles NSArray to react like a set (override isKindOfClass and implement NSSet methods to please CoreData).

There's nothing that implies any sort of ordering in the to-many relationship thus I don't see how would you do this.

Screenshot 2023-09-28 at 17 06 05

There is this checkbox in the modeller which seem to result in NSOrderedSet which is a type I have never used thus I avoid that.

Hence I keep all to-many relationships to be Set (I never use NSSet or NSMutableSet, just Set).

What I often do is add computed property like sortedItems: [Item] where I define the sort condition.
Maybe you could automatically create such computed property, something like:

@Relationship(sortedBy: \.itemName)
var items: Set<Item>

which will generate both the attribute and computed property:

@NSManaged var items: Set<Item>

var sortedItems: [Item] {
    ...return sorted per \.itemName...
}

The thing is done by SwiftData, it actually does map the array to Set, I think I can just deal w/ that in the wrapper:

setPrimitive(Set(newValue), forKey: xyz)

Yes, NSOrderedSet is for ordered relationships, there is Issue #1 for that. Maybe "ordered" should just become an @Attribute option. NSOrderedSet gives issues because unlike Set it isn't generic.

The sole advantage is that it looks a little nicer and it can be initialised w/ a literal.

This should be fixable by me w/o any hacks using the accessor info from you!

I would love to hear reasoning for that from SwiftData members.
I can imagine someone in larger dev team seeing an array and assuming a particular order of elements which can't be known.

If the property is an array and internally it's set then they likely do Array(primitiveValue) to populate the object. But nothing guarantees the actual order of elements. But then again, I would always model the relationship using Set thus I would not be affected by it:

@NSManaged var markets: Set<Market>

BTW — I stopped using NSSet and add/remove methods that Xcode generates to manage that set sometime in 2018. I always use the above and treat it as any mutable set in Swift: call .insert, .remove, .union etc. 6+ years on, never a single issue with that.
There might be some edge case I am not aware but I doubt it, if SwiftData allows Array.

I think SwiftData currently doesn't even allow Set<Target> for relationship collections.
Presumably the reasoning is that the Hashable implementation (which Set requires) should cover the whole objects value. But CoreData relies on the opposite, i.e. that the hash is only the hash of the object pointer (i.e. the NSObject default implementation).

For the array I think they just wanted to allow this syntax to make it look nice, say:

var addresses = [ Address ]()

But yes, it is very confusing and peopled trapped over that already.

Works in 0.6.0