CAPÍTULO 3. Factores de riesgo en el trabajo en oficinas y despachos
9. Factores psicosociales
When the variable is changed, we see output similar to the following:
Attribute name changed from untitled to Beef Chili
When we are done observing a value, we can stop receiving messages by passing -removeObserver:forKeyPath: to the observed object.
id myRecipe = ...
[myRecipe removeObserver:self forKeyPath:@"name"];
KVO allows views to automatically refresh themselves from the model when the data has changed. When a view is initialized, it uses KVO to connect all its components to the underlying objects and uses the notifications to refresh itself.
8.3 Cocoa Bindings and Core Data
The combination of KVO/KVC (collectively referred to as Cocoa Bindings) and Core Data reduces the amount of code that we are required to write by a considerable amount. In the previous chapter, we wrote almost no code to create and display our recipe objects. Nearly all the work that we did was in Interface Builder. In this section, we discuss each of the interface objects that we used and how they work with Core Data.
How does this apply to our application? Let’s review the user interface that we built in Chapter 7, Adding a Desktop Foundation, on page 121 and how we used KVO and KVC.
NSTableView
Our recipe application makes heavy use of the NSTableView. In the main window of our application, we have two table views: one to list all of the recipes and another to list the ingredients for those recipes. Whenever an application needs to display a list of items or a grid of data, the NSTableView is the element to use.
In an NSTableView, like in the NSOutlineView, we do not actually bind the table itself to the NSArrayController. Instead, we select each column individually and bind it to a property of the objects in the NSArrayController (see Figure 27, Select each NSTableColumn individually, on page 144). As we did in Chapter 7, Adding a Desktop Foundation, on page 121, we bind the column to the arrangedObjects Cocoa Bindings and Core Data
•
143controller key and the model key path to the value we want displayed in that column, as shown in Figure 28, Bind the table column to the Core Data prop-erty, on page 144.
Figure 27—Select each NSTableColumn individually.
Figure 28—Bind the table column to the Core Data property.
NSTableView, like NSOutlineView (as discussed in NSOutlineView, on page 148), plays very nicely with Core Data. This is especially true when the NSTableView is backed by an NSArrayController that is feeding the data. It is possible to use NSTableView with a custom data source, if that is appropriate for the problem at hand. However, when bound with an NSArrayController, the NSTableView can be manipulated with other objects, such as the NSSearchView (discussed in a moment), to produce interfaces that integrate smoothly and provide a great user experience.
With this configuration, the NSTableView displays the data from the NSArrayController automatically and, thanks to KVO, stays in sync with the data stored in the persistence layer.
NSArrayController
NSArrayController is an extremely useful object when working with Core Data because it is aware of the Core Data layer and knows how to talk to it without any additional code on our part. When we configure it within Interface Builder, all that we really need to give it is the NSManagedObjectContext and a data object type. The rest of the work—retrieving the objects, updating those objects, and creating new ones—is all handled for us.
NSArrayController also understands relationships between objects when it is working with Core Data. In our recipe application, we have one NSArrayController configured to manage RecipeIngredient objects. Based on our data model, these are child objects that are bound to a specific recipe. Because NSArrayController understands these relationships, we can configure it to pull and display only those RecipeIngredient objects that are connected to a Recipe object that is selected in another NSArrayController. This again is made possible by KVC and KVO. When we configure the RecipeIngredient’s NSArrayController to provide only those ingredients that are related to the specific recipe, what it is doing behind the scenes is accessing the Recipe object and requesting its ingredients property via KVC. In the RecipeIngredient’s NSArrayController, we bind the NSManagedObjectContext so that new ingredients can be added. In addition to properly being able to create (and remove) objects from the persistence layer, the NSArrayController will also manage the relationship between the newly created or removed RecipeIn-gredient and the parent Recipe object.
All of this works because Core Data is the entire persistence layer and is accessed in a consistent way no matter what object is being dealt with.
Because Core Data uses KVO and KVC, our controller objects do not need to know very much about the objects, other than the name of the objects and where they are stored. The rest is all resolved at runtime based on the settings Cocoa Bindings and Core Data
•
145that we provide in Interface Builder. In our recipe application, we have one NSArrayController that is bound to the Recipe entity in Core Data. Because we also bound that NSArrayController to our NSManagedObjectContext, it is able to retrieve those Recipe entities automatically and make them available to the rest of the user interface. When our interface is loaded, those NSArrayController objects go out to that NSManagedObjectContext and ask for the entities that currently exist.
Once they are loaded into the NSArrayController objects, any view element asso-ciated with them will be notified, via KVO, that the data is available for display.
All of this happens behind the scenes; we’re not required to write code for any of it.
NSFormatter
Users expect fields in the interface to accept their input and format it appro-priately. This is where NSFormatter objects come into play. When dealing with any type of number, it is best to add an NSNumberFormatter to the text field or table column and define its display. Likewise, when working with dates, use an NSDateFormatter on the field or column to ensure the data is formatted and validated correctly before it is stored in the Core Data repository. When working with Core Data, it is sometimes necessary to manipulate the display of the data so the user’s input can be validated and also so it can be displayed in a usable form. For instance, we’re not creating a very good user experience if we display currency as 3.99 rather than $3.99 or display a date in raw seconds.
In our application, we used an NSNumberFormatter to display the quantity in the Ingredients column of our second NSTableView. If we were to add a shopping list to our application, we would also use NSNumberFormatter objects to display currency and NSDateFormatter objects to show date and time information.
To add an NSFormatter to a field (either a column or a text field), select it in the Library palette and drag it onto the interface element. Once it is in place, we can configure its details in the Attributes inspector, as shown in Figure 29, NSNumberFormatter Attributes inspector, on page 147. The Attributes inspector allows us to configure exactly how the data is presented to the user.
In addition to properly displaying number and date data, the NSFormatter classes accept input from the user and send that input back to the model in the correct format. For example, by applying NSNumberFormatter to the Quantity column of the ingredients table, we are guaranteed to receive an NSNumber back from the user interface.
Figure 29—NSNumberFormatter Attributes inspector
Once an NSFormatter has been applied to an object, it can be a little tricky to reference it again to make changes. To change or remove an NSFormatter once it has been applied, select the number formatter in the element list on the left side of the Interface Builder view. Selecting the line item references the NSFormatter again so that it can be manipulated. See Figure 30, Accessing an existing NSFormatter on an element, on page 148.