9
Editing UITableView

In the last chapter, you created an application that displays a list of BNRItem instances in a UITableView. The next step for Homepwner is allowing the user to interact with the table – to add, delete, and move rows. Figure 9.1 shows what Homepwner will look like by the end of this chapter.

Figure 9.1  Homepwner in editing mode

Homepwner in editing mode

Editing Mode

UITableView has an editing property, and when this property is set to YES, the UITableView enters editing mode. Once the table view is in editing mode, the rows of the table can be manipulated by the user. Depending on how the table view is configured, the user can change the order of the rows, add rows, or remove rows. Editing mode does not allow the user to edit the content of a row.

But first, the user needs a way to put the UITableView in editing mode. For now, you are going to include a button that toggles editing mode in the header view of the table. A header view appears at the top of a table and is useful for adding section-wide or table-wide titles and controls. It can be any UIView instance.

Note that the table view uses the word header in two different ways: There can be a table header and there can be section headers. Likewise, there can be a table footer and section footers.

Figure 9.2  Section headers and footers

Section headers and footers

You are creating a table header view. It will have two subviews that are instances of UIButton: one to toggle editing mode and the other to add a new BNRItem to the table. You could create this view programmatically, but in this case you will create the view and its subviews in a XIB file, and BNRItemsViewController will unarchive that XIB file when it needs to display the header view.

First, let’s set up the necessary code. Reopen Homepwner.xcodeproj. In BNRItemsViewController.m, add a class extension with the following property. Also stub out two methods in the implementation.

@​i​n​t​e​r​f​a​c​e​ ​B​N​R​I​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​(​)​

@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​,​ ​s​t​r​o​n​g​)​ ​I​B​O​u​t​l​e​t​ ​U​I​V​i​e​w​ ​*​h​e​a​d​e​r​V​i​e​w​;​

@​e​n​d​

@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​B​N​R​I​t​e​m​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​

/​/​ ​O​t​h​e​r​ ​m​e​t​h​o​d​s​ ​h​e​r​e​

-​ ​(​I​B​A​c​t​i​o​n​)​a​d​d​N​e​w​I​t​e​m​:​(​i​d​)​s​e​n​d​e​r​
{​

}​

-​ ​(​I​B​A​c​t​i​o​n​)​t​o​g​g​l​e​E​d​i​t​i​n​g​M​o​d​e​:​(​i​d​)​s​e​n​d​e​r​
{​

}​

Notice that headerView is a strong property. This is because it will be a top-level object in the XIB file; you use weak references for objects that are owned (directly or indirectly) by the top-level objects.

Now you need to create the new XIB file. Unlike the previous XIB files you created, this XIB file will not deal with the view controller’s view. (As a subclass of UITableViewController, BNRItemsViewController already knows how to create its view.) XIB files are typically used to create the view for a view controller, but they can also be used any time you want to lay out view objects, archive them, and have them loaded at runtime.

Create a new file (Command-N). From the iOS section, select User Interface, choose the Empty template, and click Next (Figure 9.3).

Figure 9.3  Creating a new XIB file

Creating a new XIB file

On the next pane, select iPhone. Save this file as HeaderView.

In HeaderView.xib, select the File's Owner object and change its Class to BNRItemsViewController in the identity inspector (Figure 9.4).

Figure 9.4  Changing the File's Owner

Changing the File's Owner

Drag a UIView onto the canvas. Then drag two instances of UIButton onto that view. You will then want to resize the UIView so that it just fits the buttons; however, Xcode will not let you: the size is locked. To unlock the size, select the UIView on the canvas and open the attributes inspector. Under the Simulated Metrics section, select None for the Size option (Figure 9.5).

Figure 9.5  Unlocking a view’s size

Unlocking a view’s size

Now that the view can be resized, resize it and make the connections shown in Figure 9.6.

Figure 9.6  HeaderView.xib layout

HeaderView.xib layout

Also, change the background color of the UIView instance to be completely transparent. To do this, select the view and show the attributes inspector. In the pop-up labeled Background, choose Clear Color (Figure 9.7).

Figure 9.7  Setting background color to clear

Setting background color to clear

So far, your XIB files have been loaded automatically by the implementation of UIViewController. For example, BNRReminderViewController in Chapter 6 knew how to load BNRReminderViewController.xib because of code written in its superclass, UIViewController. For HeaderView.xib, you are going to write the code to have the BNRItemsViewController load this XIB file manually.

To load a XIB file manually, you use NSBundle. This class is the interface between an application and the application bundle it lives in. When you want to access a file in the application bundle, you ask NSBundle for it. An instance of NSBundle is created when your application launches, and you can get a pointer to this instance by sending the message mainBundle to NSBundle.

Once you have a pointer to the main bundle object, you can ask it to load a XIB file. In BNRItemsViewController.m, implement headerView.

-​ ​(​U​I​V​i​e​w​ ​*​)​h​e​a​d​e​r​V​i​e​w​
{​
 ​ ​ ​ ​/​/​ ​I​f​ ​y​o​u​ ​h​a​v​e​ ​n​o​t​ ​l​o​a​d​e​d​ ​t​h​e​ ​h​e​a​d​e​r​V​i​e​w​ ​y​e​t​.​.​.​
 ​ ​ ​ ​i​f​ ​(​!​_​h​e​a​d​e​r​V​i​e​w​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​L​o​a​d​ ​H​e​a​d​e​r​V​i​e​w​.​x​i​b​
 ​ ​ ​ ​ ​ ​ ​ ​[​[​N​S​B​u​n​d​l​e​ ​m​a​i​n​B​u​n​d​l​e​]​ ​l​o​a​d​N​i​b​N​a​m​e​d​:​@​"​H​e​a​d​e​r​V​i​e​w​"​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​w​n​e​r​:​s​e​l​f​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​p​t​i​o​n​s​:​n​i​l​]​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​r​e​t​u​r​n​ ​_​h​e​a​d​e​r​V​i​e​w​;​
}​

Notice that this is a getter method that does more than just get. This is a common pattern: Lazy Instantiation puts off creating the object until it is actually needed. In some cases this approach can significantly lower the normal memory footprint of your app.

You do not have to specify the suffix of the filename; NSBundle will figure it out. Also, notice that you passed self as the owner of the XIB file. This ensures that when the main NSBundle is parsing the resultant NIB file at runtime, any connections to the File's Owner placeholder will be made to that BNRItemsViewController instance.

The first time the headerView message is sent to the BNRItemsViewController, it will load HeaderView.xib and keep a pointer to the view object in the instance variable headerView. The buttons in this view will send messages to the BNRItemsViewController when tapped.

Now you just need to tell the table view about its header view. In BNRItemsViewController.m, add this to the viewDidLoad method:

-​ ​(​v​o​i​d​)​v​i​e​w​D​i​d​L​o​a​d​
{​
 ​ ​ ​ ​[​s​u​p​e​r​ ​v​i​e​w​D​i​d​L​o​a​d​]​;​

 ​ ​ ​ ​[​s​e​l​f​.​t​a​b​l​e​V​i​e​w​ ​r​e​g​i​s​t​e​r​C​l​a​s​s​:​[​U​I​T​a​b​l​e​V​i​e​w​C​e​l​l​ ​c​l​a​s​s​]​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​f​o​r​C​e​l​l​R​e​u​s​e​I​d​e​n​t​i​f​i​e​r​:​@​"​U​I​T​a​b​l​e​V​i​e​w​C​e​l​l​"​]​;​

 ​ ​ ​ ​U​I​V​i​e​w​ ​*​h​e​a​d​e​r​ ​=​ ​s​e​l​f​.​h​e​a​d​e​r​V​i​e​w​;​
 ​ ​ ​ ​[​s​e​l​f​.​t​a​b​l​e​V​i​e​w​ ​s​e​t​T​a​b​l​e​H​e​a​d​e​r​V​i​e​w​:​h​e​a​d​e​r​]​;​
}​

Build and run the application to see the interface.

While XIB files are often used to create the view for a view controller (for example, BNRReminderViewController.xib), you have 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:

-​ ​(​v​o​i​d​)​l​o​a​d​V​i​e​w​
{​
 ​ ​ ​ ​/​/​ ​W​h​i​c​h​ ​b​u​n​d​l​e​ ​i​s​ ​t​h​e​ ​N​I​B​ ​i​n​?​
 ​ ​ ​ ​/​/​ ​W​a​s​ ​a​ ​b​u​n​d​l​e​ ​p​a​s​s​e​d​ ​t​o​ ​i​n​i​t​W​i​t​h​N​i​b​N​a​m​e​:​b​u​n​d​l​e​:​?​
 ​ ​ ​ ​N​S​B​u​n​d​l​e​ ​*​b​u​n​d​l​e​ ​=​ ​[​s​e​l​f​ ​n​i​b​B​u​n​d​l​e​]​;​
 ​ ​ ​ ​i​f​ ​(​!​b​u​n​d​l​e​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​U​s​e​ ​t​h​e​ ​d​e​f​a​u​l​t​
 ​ ​ ​ ​ ​ ​ ​ ​b​u​n​d​l​e​ ​=​ ​[​N​S​B​u​n​d​l​e​ ​m​a​i​n​B​u​n​d​l​e​]​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​/​/​ ​W​h​a​t​ ​i​s​ ​t​h​e​ ​N​I​B​ ​n​a​m​e​d​?​
 ​ ​ ​ ​/​/​ ​W​a​s​ ​a​ ​n​a​m​e​ ​p​a​s​s​e​d​ ​t​o​ ​i​n​i​t​W​i​t​h​N​i​b​N​a​m​e​:​b​u​n​d​l​e​:​?​
 ​ ​ ​ ​N​S​S​t​r​i​n​g​ ​*​n​i​b​N​a​m​e​ ​=​ ​[​s​e​l​f​ ​n​i​b​N​a​m​e​]​;​
 ​ ​ ​ ​i​f​ ​(​!​n​i​b​N​a​m​e​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​U​s​e​ ​t​h​e​ ​d​e​f​a​u​l​t​
 ​ ​ ​ ​ ​ ​ ​ ​n​i​b​N​a​m​e​ ​=​ ​N​S​S​t​r​i​n​g​F​r​o​m​C​l​a​s​s​(​[​s​e​l​f​ ​c​l​a​s​s​]​)​;​
 ​ ​ ​ ​}​

 ​ ​ ​ ​/​/​ ​T​r​y​ ​t​o​ ​f​i​n​d​ ​t​h​e​ ​N​I​B​ ​i​n​ ​t​h​e​ ​b​u​n​d​l​e​
 ​ ​ ​ ​N​S​S​t​r​i​n​g​ ​*​n​i​b​P​a​t​h​ ​=​ ​[​b​u​n​d​l​e​ ​p​a​t​h​F​o​r​R​e​s​o​u​r​c​e​:​n​i​b​N​a​m​e​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​o​f​T​y​p​e​:​@​"​n​i​b​"​]​;​

 ​ ​ ​ ​/​/​ ​D​o​e​s​ ​i​t​ ​e​x​i​s​t​?​
 ​ ​ ​ ​i​f​ ​(​n​i​b​P​a​t​h​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​L​o​a​d​ ​i​t​ ​(​t​h​i​s​ ​w​i​l​l​ ​s​e​t​ ​t​h​e​ ​v​i​e​w​ ​o​u​t​l​e​t​ ​a​s​ ​a​ ​s​i​d​e​-​e​f​f​e​c​t​
 ​ ​ ​ ​ ​ ​ ​ ​[​b​u​n​d​l​e​ ​l​o​a​d​N​i​b​N​a​m​e​d​:​n​i​b​N​a​m​e​ ​o​w​n​e​r​:​s​e​l​f​ ​o​p​t​i​o​n​s​:​n​i​l​]​;​
 ​ ​ ​ ​}​ ​e​l​s​e​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​I​f​ ​t​h​e​r​e​ ​i​s​ ​n​o​ ​N​I​B​,​ ​j​u​s​t​ ​c​r​e​a​t​e​ ​a​ ​b​l​a​n​k​ ​U​I​V​i​e​w​
 ​ ​ ​ ​ ​ ​ ​ ​s​e​l​f​.​v​i​e​w​ ​=​ ​[​[​U​I​V​i​e​w​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​
 ​ ​ ​ ​}​
}​

Now let’s implement the toggleEditingMode: method. You 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.

To set the editing property for a view controller, you send it the message setEditing:animated:. In BNRItemsViewController.m, implement toggleEditingMode:.

-​ ​(​I​B​A​c​t​i​o​n​)​t​o​g​g​l​e​E​d​i​t​i​n​g​M​o​d​e​:​(​i​d​)​s​e​n​d​e​r​
{​
 ​ ​ ​ ​/​/​ ​I​f​ ​y​o​u​ ​a​r​e​ ​c​u​r​r​e​n​t​l​y​ ​i​n​ ​e​d​i​t​i​n​g​ ​m​o​d​e​.​.​.​
 ​ ​ ​ ​i​f​ ​(​s​e​l​f​.​i​s​E​d​i​t​i​n​g​)​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​h​a​n​g​e​ ​t​e​x​t​ ​o​f​ ​b​u​t​t​o​n​ ​t​o​ ​i​n​f​o​r​m​ ​u​s​e​r​ ​o​f​ ​s​t​a​t​e​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​e​n​d​e​r​ ​s​e​t​T​i​t​l​e​:​@​"​E​d​i​t​"​ ​f​o​r​S​t​a​t​e​:​U​I​C​o​n​t​r​o​l​S​t​a​t​e​N​o​r​m​a​l​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​T​u​r​n​ ​o​f​f​ ​e​d​i​t​i​n​g​ ​m​o​d​e​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​e​l​f​ ​s​e​t​E​d​i​t​i​n​g​:​N​O​ ​a​n​i​m​a​t​e​d​:​Y​E​S​]​;​
 ​ ​ ​ ​}​ ​e​l​s​e​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​h​a​n​g​e​ ​t​e​x​t​ ​o​f​ ​b​u​t​t​o​n​ ​t​o​ ​i​n​f​o​r​m​ ​u​s​e​r​ ​o​f​ ​s​t​a​t​e​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​e​n​d​e​r​ ​s​e​t​T​i​t​l​e​:​@​"​D​o​n​e​"​ ​f​o​r​S​t​a​t​e​:​U​I​C​o​n​t​r​o​l​S​t​a​t​e​N​o​r​m​a​l​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​E​n​t​e​r​ ​e​d​i​t​i​n​g​ ​m​o​d​e​
 ​ ​ ​ ​ ​ ​ ​ ​[​s​e​l​f​ ​s​e​t​E​d​i​t​i​n​g​:​Y​E​S​ ​a​n​i​m​a​t​e​d​:​Y​E​S​]​;​
 ​ ​ ​ ​}​
}​

Build and run your application, tap the Edit button, and the UITableView will enter editing mode (Figure 9.8).

Figure 9.8  UITableView in editing mode

UITableView in editing mode
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset