0

I have an entity 'person' and a 1-m related entity 'visit' defined in CoreData. Now I want to display and modify their values in related tables using NSArray controllers with COCOA bindings on MacOS

My project is for MacOS and I'm using Xcode with Swift. I have defined the data structure and Viewcontroller objects using the Xcode builder. The table for the 'person' is already working and I can add or delete persons. However I'm not able to find a way to bind the 'visit' table to the selected person. I tried several options, like connecting the content of the 'visit' array controller as recommended in Master-detail using bindings with TWO NSTableViews, but all ended up in compile time errors.

As I'm working with the visual Xcode builders, the is not much code for the moment. Here is what I did so far:

I have defined the two entity classes with the Xcode data model builder, then the two tables and array controllers with the storyboard interface builder. Then I bound the table views content to the respective array controllers and the columns to their own table view with the respective entity attribute. I also added + and - buttons to add some rows. So far everything worked fine. But the details ('visit') had no connection to any 'person'. Hence I deleted all entries in the 'visit' table and tried to bind the content of its array controller to the selected person. That is where I get stuck. Maybe I missed some initialization of the CoreData entities, but I have no clue how to proceed

Tony
  • 83
  • 4
  • Please post your code and the errors. Are the table views in the same view controller? – Willeke May 30 '19 at 11:15
  • As I'm working with the storybuilder, there is not much code at the early start, where I face the problem. I'll try to explain more detail – Tony May 31 '19 at 09:30

1 Answers1

0

I'm looking at my working macOS project which has two NSTableViews in Master-Detail.

  • The .xib has two array controllers, one for the master and detail entities. Let's call them MasterAC and DetailAC. The Master and Detail table columns are bound to these array controllers.
  • In the bindings for the DetailAC, the Content Array binding is bound to: MasterAC.selection.details, where details is the name of the master-to-detail relationship.
  • In the bindings for both MasterAC and DetailAC, the Managed Object Context binding in both are bound to the same managed object context.
  • In the array controllers, only these two bindings (Content Array and Managed Object Context) are bound.

If that does not fix it, I can poke around some more. Cocoa Bindings with Core Data in macOS are beautiful once you get them working :))

Appendix. If you've got an-ordered set

If the master-to-detail to-many relationship is an unordered set, and you are using the old school method of defining an index attribute on your Detail entity, you can define a detailsOrdered attribute in your Master class like this:

func detailsOrdered() -> [Any]? {
    return details().arraySorted(byKeyPath: "index")
}

and then bind to MasterAC.selection.detailsOrdered instead of MasterAC.selection.details.

The above implementation requires the following extension of Set:

extension Set<AnyHashable> {
    func arraySorted(byKeyPath keyPath: String?) -> [Any]? {
        let unorderedArray = Array(self)
        let sortDescriptor = NSSortDescriptor(key: keyPath, ascending: true)
        let orderedArray = (unorderedArray as NSArray).sortedArray(using: [sortDescriptor])
        return orderedArray
    }
}
Jerry Krinock
  • 4,860
  • 33
  • 39
  • Is your `details` an ordered relationship? – Willeke May 30 '19 at 11:14
  • Good question. No, because this project was started many years years ago, before ordered relationships were supported by Core Data. So it is actually old school: My `detail` subclass of NSManagedObject has an `index` attribute, and 'master` has a `detailsOrdered` readonly attribute, which returns `details` as an array, sorted by `index`. I omitted this complication from my answer. In my old project, the binding is actually `MasterAC.selection.detailsOrdered`. I think it should "just work" if `details` is an ordered set. But if not, the old school still works. – Jerry Krinock May 30 '19 at 14:22
  • Is the old school using the Content Set binding? – Willeke May 30 '19 at 14:50
  • No. It is using *Content Array*. – Jerry Krinock May 30 '19 at 16:01
  • What do you mean by "the old school"? How do you bind to a unordered relationship? – Willeke May 30 '19 at 16:09
  • OK, I just looked at a more recent (2016) Core Data macOS project which I developed. This project has a master table and a detail view, not a table. But it uses ordered relationships, and it is also bound to *Content Array*, even though the automatically-generated header file (I used [mogenerator](https://github.com/rentzsch/mogenerator) for this Objective-C project) returns says that it returns an `NSOrderedSet`. I vaguely remember that maybe there were some known issues with the *Content Set* binding – it has never worked as one would expect. – Jerry Krinock May 30 '19 at 16:21
  • Regarding your comment *What do you mean by "the old school"?*, I've added an Appendix to my answer to explain my first comment in detail. – Jerry Krinock May 30 '19 at 21:18
  • I don't have or had any problems with the Content Set binding. There is/was a known issue but it has a workaround (bind to `selection.self.details`). – Willeke May 30 '19 at 21:59
  • I have no data yet in the details entity. When I try your binding I get the following error: – Tony May 31 '19 at 09:43
  • I have no data yet in the details entity. When I try your binding I get the following error: Cannot create NSArray from object Relationship 'details' fault on managed object (xxx) (entity: Master; id: zzz ; data: { events = ""; – Tony May 31 '19 at 09:49
  • @Tony use the Content Set binding instead of the Content Array binding. – Willeke May 31 '19 at 10:50
  • Thank you! That brings me a step further without error messages. However the entries, which I now add in the detail table do display all together regardless of the person selected. – Tony May 31 '19 at 12:03
  • The details, I've added are internally all assigned to the first person – Tony May 31 '19 at 12:28
  • Finally. After revisiting all bindings I succeeded. Thank you all for the valuable hints! – Tony Jun 01 '19 at 06:15