Documentation Archive Developer
Search

Adding a Track Object

In this app, there are two custom classes that contain application logic. The Xcode template provided an AppDelegate class and created an instance of it in the nib file for you. When you made connections between the UI elements and the app delegate, you added custom code to the AppDelegate class. The app delegate acts as a controller object in the Model-View-Controller design pattern by updating views and managing model objects that store the actual application data. You now need to implement the model object that stores the track’s volume. You need to implement a Track class and create an instance of it in the app delegate. When a UI element changes a value, the app delegate is responsible for updating the track’s volume and synchronizing the views.

image: ../Art/TrackMixMVC.png

Create Header and Implementation Files for the Track Class

The first task is to create header and implementation files for the new Track class. It will inherit from the NSObject class, the root class in Objective-C.

bullet
To create the files for the new class
  1. In Xcode, in the project navigator select the TrackMix group folder.

    When you add new files in the next steps, they are added to the project navigator under this selection.

  2. Create an Objective-C class as follows:

    • Choose File > New > File.

    • In the template dialog, select Cocoa in the OS X section.

    • Select the Objective-C class template and click Next.

    image: ../Art/28_createnewclass.png
  3. In the screen that appears, set the class’s name to Track (by convention, class names begin with an upper case letter). Leave the new class as a subclass of the NSObject class, and click Next.

    image: ../Art/29_createnewclass2.png
  4. In the Save dialog, leave the group and targets as they are, and click Create.

The files should now be located in your project’s TrackMix group folder. If you look at the files, you’ll see that stub class interface and implementation declarations are provided for you. You need to add an attribute to represent the volume.

Implement the Track Class

The track’s volume attribute is implemented using an Objective-C declared property. A declared property is a convenient way to implement an instance variable.

bullet
To add a volume property
  • In the Track header file (Track.h), add a property declaration for a float value called volume.

    The header file should look like this:

    #import <Foundation/Foundation.h>
     
    @interface Track : NSObject
    @property (assign) float volume;
    @end

When you build your app, the compiler reads the property declaration and generates a private instance variable and accessor methods for the volume property. The value of the _volume instance variable is automatically set to 0 when the Track object is created.

Add a Track Property

For the app delegate to use an instance of Track—to store the volume displayed by multiple UI elements—you add a track property to the AppDelegate class.

The compiler will generate an error, though, if you declare a property without telling it about the Track class. You could import the header file for the Track class (Track.h), but typically you provide a forward declaration using @class. A forward declaration is a promise to the compiler that Track will be defined somewhere else and that it needn’t waste time checking for it now. (Doing this also avoids circularities if two classes need to refer to each other and would otherwise include each other’s header files.) You then import the header file itself in the implementation file.

bullet
To add a track property to app delegate
  1. In the app delegate’s header file (AppDelegate.h), add a forward declaration for the Track class before the interface declaration for AppDelegate.

    @class Track;
  2. Add a declaration for the track property between the last @property declaration and the @end symbol.

    @property (strong) Track *track;

    The property specifies the strong attribute rather than the weak attribute, indicating that the Track object is owned by the app delegate. As long as the app delegate references it, the Track object won’t go away. The outlet property declarations you created earlier use the weak attribute because the corresponding UI elements are contained in the view hierarchy that is owned by the window, not the app delegate. The window and its view hierarchy can go away independent of the app delegate.

Confirm that your AppDelegate class interface file (AppDelegate.h) looks like this. (The comments are not shown and the order of property and method declarations is not important.):

#import <Cocoa/Cocoa.h>
 
@class Track;
 
@interface AppDelegate : NSObject <NSApplicationDelegate>
 
@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *textField;
@property (weak) IBOutlet NSSlider *slider;
@property (strong) Track *track;
 
- (IBAction)mute:(id)sender;
- (IBAction)takeFloatValueForVolumeFrom:(id)sender;
 
@end

Create the Track Instance

Now that you’ve added the track property to the AppDelegate class, you need to set its value to an instance of Track.

bullet
To create an instance of the Track class
  1. In the implementation file for the app delegate (AppDelegate.m), import Track.h by adding this line of code before the @implementation statement:

    #import "Track.h"

    Otherwise, you’ll see a compile error later when you reference the Track class.

  2. Create an instance of Track by adding the following code as the first two statements in the implementation of the applicationDidFinishLaunching: method:

    Track *aTrack = [[Track alloc] init];
    [self setTrack:aTrack];

These two lines of code do the following:

Objective-C also supports dot notation. You can replace [self setTrack:aTrack]; with:

self.track = aTrack;

The dot notation invokes exactly the same accessor method (setTrack:) as in the original implementation. The dot notation provides a compact syntax for invoking accessor methods—especially when you use nested expressions.

Test the App

You can now test your app.

bullet
To test the app
  • Compile and run the project (choose Build > Build and Run, or click the Run button in Xcode’s toolbar).

Your app should compile without errors, and you should see the same user interface as before. Disappointingly, the user interface should also behave as it did before. Although you now have a Track object, the app delegate doesn’t do anything with it beyond creating it. There is a little more work to do to complete the implementation.

Recap

You implemented a model class called Track to store a volume attribute displayed by multiple UI elements. In the app delegate, you declared a property for a Track object and performed a few other housekeeping tasks. Accessor methods for the property are automatically synthesized.