Read iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) Online
Authors: Aaron Hillegass,Joe Conway
Tags: #COM051370, #Big Nerd Ranch Guides, #iPhone / iPad Programming
Build and run the application to see the interface. Ignore the incomplete implementation warnings; you’ll implement
toggleEditingMode:
and
addNewItem:
shortly. Until you do, tapping a button will generate an exception because the action methods of the buttons are not implemented.
While XIB files are typically used to create the view for a view controller (for example,
TimeViewController.xib
), you’ve now seen that a XIB file can be used any time you wish to archive view objects. In addition, any object can load a XIB file manually by sending the message
loadNibNamed:owner:options:
to the application bundle.
UIViewController
’s default XIB loading behavior uses the same code. The only difference is that it connects its
view
outlet to the view object in the XIB file. Imagine what the default implementation of
loadView
for
UIViewController
probably looks like:
Now let’s implement the
toggleEditingMode:
method. We could toggle the
editing
property of
UITableView
directly. However,
UITableViewController
also has an
editing
property. A
UITableViewController
instance automatically sets the
editing
property of its table view to match its own
editing
property. Which one should we set? Follow the Model-View-Controller pattern: talk to the controller and let the controller talk to the view.
To set the
editing
property for a view controller, you send it the message
setEditing:animated:
. In
ItemsViewController.m
, implement
toggleEditingMode:
.
Build and run your application, tap the
Edit
button, and the
UITableView
will enter editing mode (
Figure 10.7
).
Figure 10.7 UITableView in editing mode
There are a number of ways to add rows to a table view at runtime. The built-in behavior for adding a row is to display a new row with a green plus sign icon. However, this technique has fallen out of favor because it’s cumbersome to enter editing mode and then find the row with the plus sign icon – especially in large tables.
So we’re going to use the
New
button in the header view instead. When this button is tapped, a new row will be added to the
UITableView
. In
ItemsViewController.m
, implement
addNewItem:
.
Build and run the application. Tap the
New
button and... the application crashes. The console tells us that the table view has an internal inconsistency exception.
Remember that, ultimately, it is the
dataSource
of the
UITableView
that determines the number of rows the table view should display. After inserting a new row, the table view has six rows (the original five plus the new one). Then, it runs back to its
dataSource
and asks it for the number of rows it should be displaying.
ItemsViewController
consults the store and returns that there should be five rows. The
UITableView
then says,
“
Hey, that’s not right!
”
and throws an exception.
You must make sure that the
UITableView
and its
dataSource
agree on the number of rows. Thus, you must also add a new
BNRItem
to the
BNRItemStore
before you insert the new row. Update
addNewItem:
in
ItemsViewController.m
.
Build and run the application. Tap the
New
button and watch the new row slide into the bottom position of the table. Remember that the role of a view object is to communicate model objects to the user; updating views without updating the model objects isn’t very useful.
Also, notice that you are sending the message
tableView
to the
ItemsViewController
to get at the table view. This method is inherited from
UITableViewController
, and it returns the controller’s table view. While you can send the message
view
to an instance of
UITableViewController
and get a pointer to the same object, using
tableView
tells the compiler that the object returned will be an instance of class
UITableView
. Thus, sending a message that is specific to
UITableView
, like
insertRowsAtIndexPaths:withRowAnimation:
, won’t generate a warning.
Now that you have the ability to add rows and items, remove the code in the
init
method in
ItemsViewController.m
that puts 5 random items into the store.
Build and run the application. There won’t be any rows when you first fire up the application, but you can add some by tapping the
New
button.
In editing mode, the red circles with the dash (shown in
Figure 10.7
) are deletion controls, and touching one should delete that row. However, at this point, touching a deletion control doesn’t do anything. (Try it and see.) Before the table view will delete a row, it sends its data source a message about the proposed deletion and waits for a confirmation message before pulling the trigger.
When deleting a cell, you must do two things: remove the row from the
UITableView
and remove the
BNRItem
associated with it from the
BNRItemStore
. To pull this off, the
BNRItemStore
must know how to remove objects from itself. In
BNRItemStore.h
, declare a new method.
In
BNRItemStore.m
, implement
removeItem:
.
You could use
NSMutableArray
’s
removeObject:
method here instead of
removeObjectIdenticalTo:
, but consider the difference:
removeObject:
goes to each object in the array and sends it the message
isEqual:
. A class can implement this method to return
YES
or
NO
based on its own determination. For example, two
BNRItem
s could be considered equal if they had the same
valueInDollars
.
The method
removeObjectIdenticalTo:
, on the other hand, removes an object if and only if it is the exact same object as the one passed in this message. While
BNRItem
does not currently override
isEqual:
to do special checking, it could in the future. Therefore, you should use
removeObjectIdenticalTo:
when you are specifying a particular instance.
Now you will implement
tableView:commitEditingStyle:forRowAtIndexPath:
, a method from the
UITableViewDataSource
protocol. (This message is sent to the
ItemsViewController
. Keep in mind that while the
BNRItemStore
is the where the data is kept, the
ItemsViewController
is the table view’s
“
data source.
”
)
When
tableView:commitEditingStyle:forRowAtIndexPath:
is sent to the data source, two extra arguments are passed along with it. The first is the
UITableViewCellEditingStyle
, which, in this case, is
UITableViewCellEditingStyleDelete
. The other argument is the
NSIndexPath
of the row in the table.
In
ItemsViewController.m
, implement this method to have the
BNRItemStore
remove the right object and to confirm the row deletion by sending the message
deleteRowsAtIndexPaths:withRowAnimation:
back to the table view.
Build and run your application, create some rows, and then delete a row. It will disappear. Try out some of the different row animations!