How to set a Core Data attribute in Entity2 via a relationship from Entity1 with Cocoa Bindings - macos

I have two entities in my Core Data project: Entity1 and Entity2. I've setup an array controller for Entity1 which displays a table view and a few properties in text fields next to it. It's a simple app for data entry, nothing fancy - all built using Cocoa Bindings. All values are saved and retrieved correctly for attributes on Entity1. Here's how I'm binding the text fields:
Value - Bind to Entity1ArrayController
Controller Key: selection
Model Key Path: attribute
Both entities have a one-to-one relationship and I would like to be able to bind an attribute from Entity2 to another text field so I can set a value just like it works so well above on Entity1. I assumed I would just bind this to the same array controller and enter the relationship and attribute as key path, like so:
Controller Key: selection
Model Key Path: relationship.attribute
Even though the code compiles, and I can enter a value, it isn't saved or retrieved. Where am I going wrong?

Related

Core Data cross storage fetched property

I'm currently wrapping my head around some problem with Core Data.
I have one user model in its own store that I do not have any control over, as it gets shipped with a framework. A Persistent Store Coordinator, Managed Object Model and Context for this model gets created automatically and cannot be touched. In it, this model has a single user entity
On the other hand, I have a properties model with a properties entity in it that I have complete control over. In there I store properties for some user entities in the other store. Both user and property entities have an id attribute similar to a foreign key.
This model has it's own Persistent Store Cordinator, Managed Object Model and Context.
What I now want is to have the associated user entity as an attribute of the properties entity so I might be able to bind to key-paths similar to myproperty.user.someValueOfTheUserEntity (I'm aware that myproperty might be an array when using fetched properties).
However, as cross-store relationships are not supported I thought of using a weak relationship via Fetched Properties. That one would just have to match the two corresponding id attributes. I have created a Fetched Property for the user in Xcode and the required accessors in my properties entity's class file (As suggested in other questions, I'm treating the values returned by the Fetched Property as an array).
However, I'm unable to set a destination entity for the Fetched Property in Xcode, as the target entity resides in a completely different store. Would I also have to define my user entity in the properties store? If so, how does Core Data know that that entity shall be fetched not from my properties store but from the users store?
Some threads mentioned using configurations for this, but I cannot find any documentation that goes further than mentioning "use configurations for this".
Can somebody enlighten me on how to set up cross-storage fetched properties? #
You can use several persistent stores that share the same data model:
Use single data model (xcdatamodeld) and add all your entities
Create configurations (Editor/Add Configuration) for each "logical set" of
entities that should be stored in separate store file
Assign (Drag) entities to appropriate configurations
Add configured persistent stores to your context (see below)
Configure fetched properties
// 1. Add "static", read-only store
[coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"your static configuration name goes here..."
URL:storeUrl
options:#{
NSReadOnlyPersistentStoreOption: #(YES),
NSInferMappingModelAutomaticallyOption : #(YES)
}
error:&error];
// 2. Add "dynamic", writable content
[coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"your dynamic configuration name goes here..."
URL:storeUrl
options:#{
NSMigratePersistentStoresAutomaticallyOption: #(YES),
NSInferMappingModelAutomaticallyOption : #(YES)
}
error:&error];

Calling on a property of an entity's parent in a relationship

I have an NSColumnItem Selected Value bound to a relationship property (jobParent) in an entity (jobs). This is an inverse relationship to a property (projectChild) in a separate entity (projects).
How do I call on the projectTitle property of my projects entity to display in my NSTableColumn, based on the relationship to the currently selected jobTitle (from my jobs entity) in my NSTableView? I tried entering jobParent.projectTitle for the Model Key Path and arrangedObjects for the Controller Key but it's not working (as well as any other combination I can think of). Thanks.
The answer is to make sure the related entity is bound to 'content set' and then address the properties of the related table by using a period after the relationship property of the child entity followed by the property you want of the parent entity. For my example above, to get the projectTitle property of my projects entity in relation to my jobs entity, I would call on:
jobParent.projectTitle

Filtering entries from a Core Data entity that appear in an NSPopUpButton list

I'm familiar with how to feed data from one Core Data entity into an NSPopUpButton item so that it can be selected for another. Bindings like so:
For the values themselves:
-> ValueSelection.Content
Bind To: Value Source Entity
Controller Key: arrangedObjects
Model Key: N/A
For the values displayed in the NSPopUpButton:
-> ValueSelection.ContentValues
Bind to: Same entity as ValueSelection.Content
Controller Key: arrangedObjects
Model Key: the name of the attribute you wish to have displayed
To link it to the destination value:
-> ValueSelection.SelectedObject
Bind to: Destination entity
Controller Key: selection
Model Key: Name of the attribute/relationship in the destination entity.
What I'm trying to do is figure out if there is a way to set up a filter (I'm guessing in ContentValues) where you can only have it grab entries from that entity that have a certain attribute flag checked (e.g. say I'm pulling from my users entity and I just wanted to list male or female users).
NSArrayController has a "filter predicate", which can be set in Interface Builder or in code (via the method in the docs to which I linked). See the Predicates Programming Guide to figure out what predicate you'll need to supply for your desired filter.

Tinkering under the hood with Bindings in Xcode

Let's take two Core Data entities, set up as follows:
Entity A: Car
Attributes:
year
model
Relationships:
manufacturer (<<-> Manufacturer)
Entity B: Manufacturer
Attributes:
name
country
Relationships:
cars (<->> Car)
Now, what I want to do is bind the display to an NSTableView where we have the model of the car in one column, followed by the manufacturer, followed by the year. Binding the model and year are no problem, but if I bind the relationship to a column in the table, I get the text of a relationship fault error in each cell in that column instead of anything I'm looking for. How can I play with the binding to allow me to display the proper manufacturer name associated with the car?
Extending the question a bit further, how could I set up another table view to display, say, other Car entries with the same manufacturer relationship?
A bit more information about how you have it set up currently would be helpful. You should be able to bind to your Array Controller in exactly the same fashion as your other attributes, with the same binding and controller key. Just use the full key path manufacturer.name for the model key path.
For a to-many relationship, you use two array controllers. Set up the 'master' array controller to prepare its own content from your Core Data Manufacturer class (in Entity mode). Then, you create a secondary, 'detail' array controller. Leave the detail array controller in Class mode (with the default NSMutableDictionary class), and bind its content set to your master array controller, with the controller key set to selection and the model key path to cars.
Many many tutorials exist out there that do exactly this. I highly recommend running through one or two; I found this MacResearch.org tutorial particularly helpful. The entire series is great.

What does "Controller Key" mean in Interface Builder > Inspector > Bindings?

I can't find in the Docs where they explain all those fields and what they mean. Especially "Controller Key" is not clear to me.
[Copying my answer on another question…]
The controller key is the key for the (property of the controller object) you're binding to. The model key path is the key path by which the bound object can ask the model objects for more basic objects, such as strings or images, or for other model objects (i.e., drill down into the model).
An example: Let's say you have a Person objects in an array controller, and each Person has a name. You bind a table column to the array controller, controller key arrangedObjects (thereby getting the model objects), model key path name (thereby getting the value objects).
A more complex example: Suppose you have an array controller of Departments. Each Department contains Persons (employees in the department). You can bind your People array controller to the Departments controller, controller key arrangedObjects (getting the Department model objects), model key path #distinctUnionOfObjects.employees (getting the Person model objects), and then bind a table column to the People controller, controller key arrangedObjects, model key path name.
That table would be for people who work for your company; if you have a separate table of prospective employees, you can create Person objects for them, too, and they won't show up in the table of existing employees because they're not in a Department. When you hire them, you'll add them to one or more Departments; then, they'll show up in the People array controller automatically, because that array controller is observing the employees of all of the Departments.
The Controller Key pop-up menu is a way to help you discover what keys the controller (typically a NSArrayController, NSObjectController or a NSTreeController) presents.
The best example is the selection key of NSArrayControllers, which contains the set of selected objects. What is confusing is the NSObjectController presents a 'selection' key too, although the controller can control only a single object (therefore the selection = the object).
I agree that it is not clear at all. I personnally began to understand it when I bound my objects programmatically (i.e. using the bind:toObject:withKeyPath:options: method).
It has to do with key-value coding. You can bind a control in IB to a value in your controller. To connect that value, you have to specify the keypath to it. For example, if you have a textfield in IB and you want to bind it to say a field called 'name' in your controller, you would specify 'name' as the keypath. You then need to set up your name field in your controller to be accessible through key-value coding. This is done in 10.5 by using the #property and #synthesize specifiers.
Take a look at this topic: Cocoa Key Value Bindings: What are the explanations of the various options for Controller Key?
I posted an explanation of where to find definitions for all Controller Key's there.

Resources