Saturday, 26 April 2014

Data Model Objects [Model Citizen]

Your data model consists of the objects that store your apps information. Data model objects should:

n     Represent the data in your app

n     Encapsulate the storage of that data

n     Avoid assumptions about how the data is displayed or changed

The data of your app is whatever values, information, or concepts your app uses. In your MyStuff app, your data model was simply the names, locations, and images of the things you own. A chess app would have a slightlymore complex data model; there would be an object that represented the chess board, objects for each player, objects for each piece, objects that recorded the moves, and so on. An astronomical catalog app might requiredozens of classes and hundreds of thousands of objects to keep track of the visible stars.

The first job of your data model classes is to represent the data for your app, while hiding (encapsulating) how that data is stored. It should present the rest of your app with a simple interface so the other classes can get theinformation they need, without needing to know exactly how that data is represented or stored.

Even for “simple apps, like MyStuff, encapsulation is important for the futurof your app. For examplethe image property of MyWhatsistored a UIImage object with the picture of that item. Simple, right?
But images can take up a lot of memory, and if your app is going to inventory hundreds, instead of
dozens, of items, your app cant keep all of those images in memory—it will run out of memory and crash.

Yocould address this problem by changing your data model so images that you’re not currently displaying—after all, you cant display them all at once—are written to flash memory as individual image filesThe next time anobject requests the image property of MyWhatsit object, your data model can determine if it has that image in memory owhether it needs to retrieve it from flash storage.

The key concept is that all of these decisions are encapsulated in your data model. The other classes that use your MyWhatsit object just request the image property; they dont know how, or where, that information is stored, and they shouldnt care. Review the food truck analogy in the “Encapsulation” section of Chapter 6, if that isnt clear.

The other really important aspect of the data model is what it is not. The data model is at the bottom of the MVC design and it shouldnt contain any properties or logic that are not directly related to your apps data or how thatdata is maintained.

Specifically, it shouldnt know anything about, or make any assumptions about, the view or controller objects it works with. It shouldnt contain references to view objects, have methods that present the data in the user interface, or directly handle user actions. In this respect, the data model is the purest of the three MVC roles; its all about the data, and nothing else. 

View Objects

View objects sit in the middle of the MVC design. A good view object:

n     Presents some aspect of the data model to the user

n     Understands the data it displays, and how to display it, but nothing more

n     May interpret user interface events and send actions to controller objects

A view objects primary purpose is to display the value(s) in your data model. View objects must, by necessity, understand at least some aspects of your data model, but know nothing about controller objects.

How much does a view object know about the data model? That depends on the complexity of whatbeindisplayed. In general, it should know just enough to do its job, and no more. A view that displays a string only needs to knowthe string value to display. A view that draws an animated picture of thnight sky needs a lot of information: the list of visible stars, their magnitude and color, the coordinates
of the observer, the current timethe azimuth, elevation, the angle of view, and so on. To find examplesyou have to look no furthethan the Cocoa Touch framework, which is full of view objects that displaeverything from the simpleststring (UILabel) to entire documents (UIWebView).

Its common for view objects, especially complex ones, to maintain a reference to the data model objects they display. Such a view object not only understands how to display the data, but also knows what data to display.


View objects may also interpret user interface events (like a “swipe” or a “pinch” gesture) and translate those into action messages (-nextPage: or -zoomOut:), which it sends to a controller object. A view object should not act onthose actions; it should simply pass them to a controller. 

Controller Objects

Controllers are at the top of the MVC design and are the “business end” of your app. Controller objects are supervisors that oversee, and often coordinate, the data model and view objects. Controller objects:

n     Understand, and often create, the data model objects

n     Configure, and often create, the view objects

n     Perform the actions received from view objects

n     Make changes to the data model

n     Coordinate communications between the data model and view objects

n     May take responsibility for keeping the view objects updated



Its almost easier to explain what a controller is not, than what it is. It is not your data model; a controller object does not store, manage, or convert your apps data. It is not a view object; it does not draw the interface orinterpret low-level events. It is, essentially, everything else.

Controllers can be involved in the initialization of your data model and view objects, often creating the data model objects and loading your view objects from an Interface Builder file.

Controller objects contain all of the business logic of your app. They perform the commands initiated by the user, respond to high-level events, and instigate changes to the data model. In complex apps, there are often multiplecontroller objects, each responsible for a particular feature or interface.

Your controller objects are also either the recipient or source of most of the messages within your app. How they are involved depends on your design, which brings us to the topic of inter-object communications.


MVC Communications

In its simplest form, the communications between MVC objects forms a loop (see Figure 8-1):

n     Data model objects notify view objects of changes

n     View objects send actions to controller objects

n     Controller objects modify the data model


Figure 8-1. Simple MVC communications

In this arrangement, the data model is responsible for notifying any observers of changes. The view objects are responsible for observing and displaying those changes and sending actions to the controller objects. Thecontroller objects perform the actions, often making changes to the data model, and the whole cycle starts again. 
1Theres an exception to this rule that I’ll describe toward the end of this chapter. 
Counter-intuitively, this simplified arrangement only happens in fairly sophisticated apps. Most of the time, the data model is not set up to post notification and the view objects dont observe changes directly. Instead, thecontroller object steps in and takes responsibility for notifying the view objects when the data model changes, as shown in Figure 8-2.


Figure 8-2. Typical MVC communications

Now that you have the basics of the MVC design pattern, lets put together another iOS app. Instead of focusing on a particular iOS technology, like the motion events or the camera, I want you to pay attention to the roles ofyour objects, their design, and how they change as your app evolves.


Color Model

You’re going to develop a new app called ColorModel. Its an app that lets you choose a color using the hue-saturation-brightness color model. Its initial design is simple, as shown in Figure 8-3. The interface consists of threesliders, one for each of the HSB values, and a view where the chosen color appears.


Figure 8-3. Initial design of ColorModel

Start by launching Xcode. Create and configure a new project:

n     Use the Single View Application template

n     Name the project ColorModel

n     Set the class prefix to CM

n     Set devices to iPhone

n     Create the project

n     In the General tab of the ColorModel target, uncheck the Landscape  Left and
Landscape  Right  orientations, so only Portrait orientation is checked

Creating Your Data Model

The first step (after design) of almost any app is to develop your data model. The data model in this app is remarkably simple; its a single object that maintains the values for hue, saturation, and brightness. It also translates those values into a color object suitable for display and other uses. Start by adding a new Objective-C source file to your project. Select the ColorModel group (the folder, not the project) in the project navigator and choose theFile  New  File . . command
(or right/control+click on the group and choose New File . . .). From the iOS category, select the
Objective-C class template, name it CMColor, and make it a subclass of NSObject. You will now have an empty data model class, as shown in Figure 8-4.


Figure 8-4. Empty CMColor class

Create your data models public interface by adding the following properties to the @interface
section of the CMColor.h file:

@property  (nonatomic) float  hue;
@property  (nonatomic) float saturation;
@property  (nonatomic) float brightness;
@property  (readonly,nonatomic) UIColor  *color;

The first three properties are floating point values, one each for the colors hue, saturation, and brightness. The hue is in degrees and can range between 0° and 360°. The other two are expressed as a percentage and can rangebetween 0% and 100%.

The last property is readonly—which just means clients of this object cant change it. It contains a
UIColor object that represents the color of the current hue/saturation/brightness triplet. The color 
property is a synthetic property: a value calculated from the values of the other three properties.
Implement this by replacing the default getter method with your own in CMColor.m:

-  (UIColor*)color
{
return  [UIColor colorWithHue:self.hue/360 saturation:self.saturation/100 brightness:self.brightness/100
alpha:1];
}

The conversion from the hue-saturation-brightness values into a UIColor object (which uses the
red-green-blue model) is thoughtfully provided by the UIColor class. I’m glad. There are formulas for converting between various color models, but it requires a lot more math than I want to explain.

The values that UIColor uses to express hue, saturation, and brightness are, however, different than the one you choose—OK, I choose—for the data model. In your data model, hue is a value between 0 and 360. UIColor expectsa value between 0 and 1. Likewise, UIColor saturation and brightness values are also between 0 and 1. To convert between our model and the one used by UIColor, you must scale the values by dividing them by their range. This is the kind of detail that data models encapsulate (hide) from the rest of your app.

With your data model complete, its time to move on to the view objects. 

Creating View Objects

Select your Main.storyboard Interface Builder file. In the objects library, find the plain View object and drag one into your interface. Resize and position it so it occupies the top of the display, inset from the left, top, and rightusing the positioning guides. Using either the resizing handles or the size inspector, set its height to 80 pixels, as shown in Figure 8-5. This will be the view where the users chosen color appears.


Figure 8-5. Adding a simple view object


Control/Right-click on the new view object, drag down, release, and choose the Height constraint to fix the height of the view at 80 pixels.

Find the Label object in the library and drag one into your interface. Position it immediately below the lower-left corner of the view object. Set its title to H. Locate the Slider object in the library and drag one into your interface, positioning it just below the color view and immediately to the right of the label you just added, as shown in Figure 8-6.


Figure 8-6. Adding the first label and slider

Select the slider and grab the right-center resizing handle. Resize it so its right edge is aligned with the viewYou need two more label/slider pairs, so lets quickly duplicate the ones you just created. Select both the label andslider views (by holding down the shift key, or by dragging out a selection rectangle that selects both). Now press the option key. While holding down the option keyclick
and drag the pair down. The option key turns the drag into a copy operation. Position the pair immediately below the first two, as shown in Figure 8-7, and release the mouse.


Figure 8-7. Duplicating the label and slider


Repeat the copy again so you have three labels and three slider controls. Control/Right-click on the top slider, drag down to the middle sliderrelease, and choose Equal Widths from the constraints menu. Repeat, dragging tothe bottom slider, as shown in
Figure 8-8. This adds constraints to keep the three slider controls the same width.


Figure 8-8. Constraining the widths of the sliders



Retitle the second and third labels to S and B. You now have all of the view objects you need. Flesh out the constraints by choosing Add Missing Constraints in View Controller from the Resolve Auto Layout Issues control.

In your data mode, the hue value ranges from 0° to 360° and saturation and brightness range from 0% to 100%. Change the value range of the three sliders to match. Select the top (hue) slider and use the attributes inspectorto change its Maximum value from 1 to 360, as shown in Figure 8-9.Change the maximum value of the other two sliders to 100.


Figure 8-9. Establishing value range of slider control

Writing Your Controller

The Xcode project template already provides you with a controller class; you just need to filit out. Select your CMViewController.h interface file. Your controller will need a reference to your data modeobject, along with outlets andactions to connect with your interface. Start by adding an #import statement above the @interface directive syour controller knows about your CMColor class:

#import  "CMColor.h"

Inside the @interface, add two properties:

@property  (strong,nonatomic) CMColor *colorModel;
@property  (weak,nonatomic) IBOutlet  UIView *colorView;

The first is your controllers connection with your data model. The second is an outlet that you’ll connect to your color view. This will let your controller update the color displayed in the view.

Finally, your controller will need three actions, one for each slider control, that will adjust one value in the data model:

-  (IBAction)changeHue:(UISlider*)sender;
-  (IBAction)changeSaturation:(UISlider*)sender;
-  (IBAction)changeBrightness:(UISlider*)sender;

Switch to the CMViewController.m implementation file, and add these three methods:

-  (IBAction)changeHue:(UISlider*)sender
{
self.colorModel.hue = sender.value; self.colorView.backgroundColor = self.colorModel.color;
}

-  (IBAction)changeSaturation:(UISlider*)sender
{
self.colorModel.saturation = sender.value; self.colorView.backgroundColor = self.colorModel.color;
}

-  (IBAction)changeBrightness:(UISlider*)sender
{
self.colorModel.brightness = sender.value; self.colorView.backgroundColor = self.colorModel.color;
}

Each action message will be received from one of the slider controls whenever it changes. Each method simply modifies the corresponding value in the data model with the new value of the slider.
It then updates the color view to reflect the new color in the data model. In this implementation, your controller is taking responsibility for updating the view whenever the data model changes
(see Figure 8-2).

The last detail is to create the data model when the controller is loaded. Find the -viewDidLoad
method and add the one bold line:

-  (void)viewDidLoad
{
[super  viewDidLoad];
self.colorModel = [CMColor  new];
}

No comments:

Post a Comment