Views
Views,
although possible to create programmatically, will most frequently be
designed visually in Interface Builder. Views can consist of many
different interface elements. When loaded at runtime, views create any number
of objects that can implement a basic level of interactivity on their
own (such as a text field opening a keyboard when touched). Even so, a
view is entirely independent of any application logic. This clear
separation is one of the core principles of the MVC design approach.
For the objects in a view to
interact with application logic, they require a connection point to be
defined. These connections come in two varieties: outlets and actions.
An outlet defines a path between the code and the view that can be used
to read and write values. Second, an action defines a method in your
application that can be triggered via an event within a view, such as a
touch or swipe.
So, how do outlets and
actions connect to code? In the preceding hour, you learned to
Control-drag in Interface Builder to create a connection, but Interface
Builder “knew” what connections were valid. It certainly can’t “guess”
where in your code you want to create a connection; instead, you must
define the outlets and actions in the code that implement the view’s
logic (that is, the controller).
View Controllers
A controller, known in
Xcode as a view controller, handles the interactions with a view and
establishes the connection points for outlets and actions. To accomplish
this, two special directives, IBAction and IBOutlet, will be added to your project’s code. Specifically, you add these directives to the header files of your view controller. IBAction and IBOutlet are markers that Interface Builder recognizes; they serve no other purpose within Objective-C.
By the Way
View controllers can hold
application logic, but I don’t mean to imply that all your code should
be within a view controller. Although this is largely the convention for
the tutorials in this book, as you create your own apps, you can
certainly define additional classes to abstract your application logic
as you see fit.
Using IBOutlet
An IBOutlet is used to enable your code to talk to objects within views. For example, consider a text label (UILabel) that you’ve added to a view. If you want to access the label under the name myLabel within your view controller, you would declare it like this in the header file:
IBOutlet UILabel *myLabel;
Once declared, Interface Builder enables you to visually connect the view’s label object to the myLabel variable. Your code can then fully interact with the label object—changing its properties, calling its methods, and so on.
Easy Access with property and synthesize
The @property directive
declares elements in a class that should be exposed via “getters” and
“setters” (or accessors and mutators, if you prefer). Properties are
defined with a series of attributes, most frequently nonatomic and are
retained during iPhone development.
The @synthesize directive creates simplified getters and setters, making retrieving and setting values of an object very simple.
Returning to the example of a UILabel instance called myLabel, I would initially declare it as a property in the header file of my view controller:
@property (retain, nonatomic) NSString *myLabel;
And then use @synthesize in the implementation file to create simplified getters and setters:
Once those lines are added, the current myLabel value could be retrieved from UILabel’s text property using theCurrentLabel=myLabel.text (the getter) or set to something new with myLabel.text=@"My New Label" (the setter).
Using IBAction
An IBAction is
used to “advertise” a method in your code that should be called when a
certain event takes place. For instance, if a button is pushed, or a
field updated, you will probably want your application to take action
and react appropriately. When you’ve written a method that implements
your event-driven logic, you can declare it with IBAction in the header file, which subsequently will expose it to Interface Builder.
For instance, a method doCalculation might be declared like this:
-(IBAction)doCalculation:(id)sender;
Notice that the declaration includes a sender parameter with the type of id.
This is a generic type that can be used when you don’t know (or need to
know) the type of object you’ll be working with. By using id, you can write code that doesn’t tie itself to a specific class, making it easier to adapt to different situations.
When creating a method that will be used as an action (like our doCalculation example), you can identify and interact with the object that invoked the action through the sender
variable (or whatever you decide to call it in your code). This will be
handy if you decide to design a method that handles multiple different
events, such as button presses from several different buttons.
Data Models
Let me get this out of the way
upfront: For many of the exercises we’ll be doing in this book, a
separate data model is not needed; the data requirements are handled
within the controller. This is one of the trade-offs of small projects
like the one you’ll be working through in a few minutes. Although it
would be ideal to represent a complete MVC application architecture,
sometimes it just isn’t possible in the space and time available. In
your own projects, you’ll need to decide whether to implement a
standalone model. In the case of small utility apps, you may find that
you rarely need to consider a data model beyond the logic you code into
the controller.
As you grow more
experienced with the iOS Software Development Kit (SDK) and start
building data-rich applications, you’ll want to begin exploring Core
Data. Core Data abstracts the interactions between your application and
an underlying datastore. It also includes a modeling tool, like
Interface Builder, that helps you design your application, but rather
than visually laying out interfaces, you can use it to visually map a
data structure, as shown in Figure 1.