Tải bản đầy đủ (.pdf) (10 trang)

Phát triển ứng dụng cho iPhone và iPad - part 9 potx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.58 MB, 10 trang )

each time, but parameterized queries offer the performance advantage of preparing and compiling
the statement once and the statement being cached for reuse.
Writing to the Database
If you modify the sample application, or create your own SQLite application that attempts to
write to the database, you will have a problem. The version of the database that you are using in
the sample code is located in the application bundle, but the application bundle is read - only, so
attempting to write to this database will result in an error.
To be able to write to the database, you need to make an editable copy. On the iPhone, this editable
copy should be placed in the documents directory. Each application on the iPhone is “ sandboxed ”
and has access only to its own documents directory.
The following code snippet shows how to check to see if a writable database already exists, and if
not, create an editable copy.
// Create a writable copy of the default database from the bundle
// in the application Documents directory.
- (void) createEditableDatabase {
// Check to see if editable database already exists
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *writableDB = [documentsDir
stringByAppendingPathComponent:@”ContactNotes.sqlite”];
success = [fileManager fileExistsAtPath:writableDB];

// The editable database already exists
if (success) return;


// The editable database does not exist


// Copy the default DB to the application Documents directory.
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@”Catalog.sqlite”];
success = [fileManager copyItemAtPath:defaultPath
toPath:writableDB error: & error];
if (!success) {
NSAssert1(0, @”Failed to create writable database file:’%@’.”,
[error localizedDescription]);
}
}
You would then need to change your database access code to call this function and then refer to the
editable copy of the database instead of the bundled copy.
Connecting to Your Database

49
CH002.indd 49CH002.indd 49 9/20/10 2:31:41 PM9/20/10 2:31:41 PM
50

CHAPTER 2 THE IPHONE AND IPAD DATABASE: SQLITE
Displaying the Catalog
Now that you have the DBAccess class done, you can get on with displaying the catalog. In the

RootViewController , you will implement code to retrieve the products array from the DBAccess
class and display it in the
TableView .
In the header,
RootViewController.h , add import statements for the Product and DBAccess
classes:
#import “Product.h”
#import “DBAccess.h”

Add a property and its backing instance variable to hold your products array:
@interface RootViewController : UITableViewController {
// Instance variable to hold products array
NSMutableArray *products;

}

@property (retain,nonatomic) NSMutableArray* products;
Notice that the products property is declared with the retain attribute. This means that the
property setter method will call
retain on the object that is passed in. You must specify the retain
attribute to ensure that the products array is available for use when you need it. Recall that in the

DBAccess class, you called autorelease on the array that is returned from the getAllProducts
method. If you did not add the
retain attribute, the products array would be released on the next
pass through the application event loop. Trying to access the
products property after the array is
released would cause the application to crash. You avoid this by having the setter call
retain on
the array.
In the
RootViewController.m implementation class, you need to synthesize the products property
below the
@implementation line:
@synthesize products;
Synthesizing a property causes the compiler to generate the setter and getter methods for the
property. You can alternatively defi ne the getter, setter, or both methods yourself. The compiler will
fi ll in the blanks by defi ning either of these methods if you don ’ t.
Continuing in the

RootViewController.m implementation class, you ’ ll add code to the viewDidLoad
method to get your products array from the
DBAccess class:
- (void)viewDidLoad {
[super viewDidLoad];

// Get the DBAccess object;
DBAccess *dbAccess = [[DBAccess alloc] init];

// Get the products array from the database
self.products = [dbAccess getAllProducts];

CH002.indd 50CH002.indd 50 9/20/10 2:31:42 PM9/20/10 2:31:42 PM
// Close the database because we are finished with it
[dbAccess closeDatabase];

// Release the dbAccess object to free its memory
[dbAccess release];

}
RootViewController.m
Next, you have to implement your TableView methods. The fi rst thing you have to do is tell the

TableView how many rows there are by implementing the numberOfRowsInSection method as you
did in the previous chapter. You will get the count of items to display in the
TableView from your
products array:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [self.products count];

}
RootViewController.m
Finally, you have to implement cellForRowAtIndexPath to provide the TableView with the

TableViewCell that corresponds with the row that the TableView is asking for. The code is similar
to the example from the previous chapter. The difference is that now you get the text for the cell
from the
Product object. You look up the Product object using the row that the TableView is
asking for as the index into the array. The following is the
cellForRowAtIndexPath method:
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @”Cell”;

UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}

// Configure the cell.
// Get the Product object
Product* product = [self.products objectAtIndex:[indexPath row]];

cell.textLabel.text = product.name;
return cell;

}
RootViewController.m
Connecting to Your Database

51
CH002.indd 51CH002.indd 51 9/20/10 2:31:43 PM9/20/10 2:31:43 PM
52

CHAPTER 2 THE IPHONE AND IPAD DATABASE: SQLITE
To set the Catalog text at the top in the Navigation Controller, double -
click
MainWindow.xib . Then, click on the navigation item in Interface
Builder and set the
Title property to Catalog .
You should now be able to build and run the application.
When you run it, you should see the product catalog as in
Figure 2 - 15. When you touch items in the catalog, nothing happens,
but the application should display the details of the product
that is touched. To accomplish this, the
TableView function

didSelectRowAtIndexPath needs to be implemented. But before you
do that, you need to build the view that you will display when a user
taps a product in the table.
Viewing Product Details
When a user taps a product in the table, the application should
navigate to a product detail screen. Because this screen will be used
with the
NavigationController , it needs to be implemented using a


UIViewController . In Xcode, add a new UIViewController subclass
to your project called
ProductDetailViewController . Make sure that
you select the option “ With XIB for user interface. ” This creates your
class along with a NIB fi le for designing the user interface for the class.
In the
ProductDetailViewController.h header, add Interface Builder outlets for the data that you
want to display. You need to add an outlet for each label control like this:
IBOutlet UILabel* nameLabel;
IBOutlet UILabel* manufacturerLabel;
IBOutlet UILabel* detailsLabel;
IBOutlet UILabel* priceLabel;
IBOutlet UILabel* quantityLabel;
IBOutlet UILabel* countryLabel;
You will use the outlets in the code to link to the UI widgets created in Interface Builder. The use of
Interface Builder is beyond the scope of this book. There are several good books on building user
interfaces for the iPhone including iPhone SDK Programming: Developing Mobile Applications for
Apple iPhone and iPod Touch by Maher Ali (Wiley, 2009).
You will transfer the data about the product that the user selected to the detail view by passing
a
Product object from the RootViewController to the ProductDetailViewController . Because
you will be referencing the
Product object in your code, you need to add an import statement
for the
Product class to the ProductDetailViewController header. You also need to add the
FIGURE 2 - 15: Running the
Catalog application
CH002.indd 52CH002.indd 52 9/20/10 2:31:43 PM9/20/10 2:31:43 PM
method signature for the setLabelsForProduct method that will be used to receive the Product
object from the

RootViewController and set the text of the labels. The complete header should
look like this:
#import < UIKit/UIKit.h >
#import “Product.h”

@interface ProductDetailViewController : UIViewController {

IBOutlet UILabel* nameLabel;
IBOutlet UILabel* manufacturerLabel;
IBOutlet UILabel* detailsLabel;
IBOutlet UILabel* priceLabel;
IBOutlet UILabel* quantityLabel;
IBOutlet UILabel* countryLabel;

}
-(void) setLabelsForProduct: (Product*) theProduct;

@end
ProductDetailViewController.h
Now, open up the ProductDetailViewController.xib fi le in
Interface Builder. Here you will add a series of
UILabels to the
interface as you designed in the mockup. Your interface should
look something like Figure 2 - 16.
Next, you ’ ll need to hook up your labels in Interface
Builder to the outlets that you created in the

ProductDetailViewController.h header fi le. Make sure that
you save the header fi le before you try to hook up the outlets or
the outlets that you created in the header will not be available in

Interface Builder.
To hook up the outlets, bring up the

ProductDetailViewController.xib fi le in Interface Builder.
Select File ’ s Owner in the Document window. Press Cmd+2 to
bring up the Connections Inspector. In this window, you can
see all of the class ’ s outlets and their connections. Click and
drag from the open circle on the right side of the outlet name to
the control to which that outlet should be connected in the user
interface. You should see the name of the control displayed on
the right side of the Connections Inspector as in Figure 2 - 17.
FIGURE 2 - 16: Product detail view
Connecting to Your Database

53
CH002.indd 53CH002.indd 53 9/20/10 2:31:44 PM9/20/10 2:31:44 PM
54

CHAPTER 2 THE IPHONE AND IPAD DATABASE: SQLITE
In ProductDetailViewController.m , implement setLabelsForProduct to set the text in the
labels:
-(void) setLabelsForProduct: (Product*) theProduct
{
// Set the text of the labels to the values passed in the Product object
[nameLabel setText:theProduct.name];
[manufacturerLabel setText:theProduct.manufacturer];
[detailsLabel setText:theProduct.details];
[priceLabel setText:[NSString stringWithFormat:@”%.2f”,theProduct.price]];
[quantityLabel setText:[NSString stringWithFormat:@”%d”,
theProduct.quantity]];

[countryLabel setText:theProduct.countryOfOrigin];

}
ProductDetailViewController.m
This code accepts a Product object and uses its properties to set the text that is displayed in the
interface labels.
In order to be able to navigate to your new screen, you need to add code to the
RootViewController
to display this screen when a user selects a product.
FIGURE 2 - 17: Building the detail view with Interface Builder
CH002.indd 54CH002.indd 54 9/20/10 2:31:45 PM9/20/10 2:31:45 PM
In the RootViewController header, you must add an import for ProductDetailViewController
because you will create an instance of this class to push onto the navigation stack:
#import “ProductDetailViewController.h”
In the RootViewController implementation, add code to the tableView:
didSelectRowAtIndexPath:
method to instantiate a ProductDetailViewController , populate
the data, and push it onto the navigation stack:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


// Get the product that corresponds with the touched cell
Product* product = [self.products objectAtIndex:[indexPath row]];

// Initialize the detail view controller from the NIB
ProductDetailViewController *productDetailViewController =
[[ProductDetailViewController alloc]
initWithNibName:@”ProductDetailViewController” bundle:nil];


// Set the title of the detail page
[productDetailViewController setTitle:product.name];

// Push the detail controller on to the stack
[self.navigationController
pushViewController:productDetailViewController animated:YES];

// Populate the details
[productDetailViewController setLabelsForProduct:product];

// release the view controller becuase it is retained by the
// Navigation Controller
[productDetailViewController release];
}
ProductDetailViewController.m
That ’ s all there is to it. Now you should be able to build and run your application. Try tapping on
an item in the catalog. The application should take you to the detail page for that item. Tapping the
Catalog button in the navigation bar should take you back to the catalog. Tapping another row in
the TableView should take you to the data for that item.
You now have a fully functioning catalog application! I know that it doesn ’ t look very nice, but
you ’ ll work on that in the next chapter where you dive into customizing the
UITableView .
MOVING FORWARD
Now that you have a functioning application, feel free to play with it as much as you like! Spruce up
the interface or add additional fi elds to the database tables and
Product class.
Moving Forward

55
CH002.indd 55CH002.indd 55 9/20/10 2:31:46 PM9/20/10 2:31:46 PM

56

CHAPTER 2 THE IPHONE AND IPAD DATABASE: SQLITE
There are a lot of good books on the SQL language, so if you were confused by any of the SQL used
in this chapter, it may be a good idea to pick up a copy of SQL For Dummies by Allen Taylor.
Another resource that you should be aware of is the SQLite web site at
.
There you will fi nd extensive documentation of the database and the C language APIs that are used
to access the database.
Although you ’ ve learned how to get your data out of SQLite and into an iPhone application, the
catalog doesn ’ t look that great. In the next chapter, you will learn how to display your data with
more fl air by customizing the TableView.
CH002.indd 56CH002.indd 56 9/20/10 2:31:46 PM9/20/10 2:31:46 PM
Displaying Your Data:
The UITableView
WHAT ’ S IN THIS CHAPTER?
Customizing the TableView by creating your own TableView cells
Searching and fi ltering your result sets
Adding important UI elements to your tables such as indexes and
section headers
Avoiding and troubleshooting performance issues with your
TableViews
The focus of the book thus far has been on how to get your data on to the iPhone and how to
access that data on the device. This chapter focuses on how you can enhance the display of
your data by customizing the
TableViewCell . It also examines how to make your data easier
to use by adding an index, section headings, and search functionality to the
UITableView . In
the next several sections, you take a closer look at how to use the
TableView to display your

data in ways that make it more useful to your target audience.
CUSTOMIZING THE TABLEVIEW
You begin by taking a look at the default TableView styles that are available in the iPhone SDK.
Then, you learn the technique of adding subviews to the content view of a
TableViewCell . In
the event that neither of these solutions meets your needs for customizing the display of your
data, you will examine how to design your own
TableViewCell from scratch using Interface
Builder. If you had trouble with IB in the previous chapter, now is a good time to review
Apple ’ s documentation on using IB, which you can fi nd at
.




3
CH003.indd 57CH003.indd 57 9/18/10 9:26:13 AM9/18/10 9:26:13 AM
58

CHAPTER 3 DISPLAYING YOUR DATA: THE UITABLEVIEW
TableViewCell Styles
Several pre - canned styles are available to use for a TableViewCell :

UITableViewCellStyleDefault : This style displays a cell with a black, left - aligned text
label with an optional image view.

UITableViewCellStyleValue1 : This style displays a cell with a black, left - aligned text label
on the left side of the cell and an additional blue text, right - aligned label on the right side.

UITableViewCellStyleValue2 : This style displays a cell with a blue text, right - aligned

label on the left side of the cell and an additional black, left - aligned text label on the right
side of the cell.

UITableViewCellStyleSubtitle : This style displays a cell with a black, left - aligned text
label across the top with a smaller, gray text label below.
In each style, the larger of the text labels is defi ned by the
textLabel property and the smaller is
defi ned by the
detailTextLabel property.
Let ’ s change the Catalog application from the last chapter to see what each of these styles looks
like. You will change the application to use the name of the part manufacturer as the subtitle.
In the
RootViewController.m implementation fi le, add a line to the tableView:cellForRowAt
IndexPath:
method that sets the cell ’ s detailTextLabel text property to the product ’ s manufacturer:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @”Cell”;

UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}

// Configure the cell.
// Get the Product object

Product* product = [self.products objectAtIndex:[indexPath row]];

cell.textLabel.text = product.name;
cell.detailTextLabel.text = product.manufacturer;
return cell;
}
RootViewController.m
When you run the application, you will see something like Figure 3 - 1 (a). Nothing has changed. You
may be wondering what happened to the subtitle. When you initialized the cell, the style was set to

UITableViewCellStyleDefault . In this style, only the cell ’ s textLabel is displayed, along with an
optional image, which you will add in a moment.




CH003.indd 58CH003.indd 58 9/18/10 9:26:17 AM9/18/10 9:26:17 AM

×