Tải bản đầy đủ - 0 (trang)
Chapter 5. plists and Modal Views: Refining your app

Chapter 5. plists and Modal Views: Refining your app

Tải bản đầy đủ - 0trang

debugging DrinkMixer



It all started with Sam...

Sam wanted an app to make his bartending work

easier. You got one up and rolling pretty quick,

but hit a snag filling in the details for each drink

because of a plist of dictionaries.

drink

ow a ton of

I need to kn

ere an

th

y night. Is

recipes ever

?

app for that



DrinkMixer has two

views: a table view of

the drinks and a detail

view about each individual

drink.



DrinkMixer



Sam, bartender

at the HF

Lounge



When we last left DrinkMixer, you

were in the middle of debugging it...

198   Chapter 5

www.it-ebooks.info











plists and modal views



Anatomy of

a Crash

DrinkMixer started and ran happily until it hit our breakpoint

at line 19. The debugger stopped our application and displayed

the debugging console. By setting a breakpoint in our code, what

we discovered at the end of Chapter 4 is that before your app

imported the file, there was no crash; so far so good.

Let’s walk through loading our plist and make sure that works by

typing next twice. The first “next” sets up the path to the plist,

the second one actually loads the data.



Here’s where it

stopped at the

breakpoint. We told

the debugger to let

DrinkMixer execute

the next two lines.



Here’s the

Continue button.



It made it past

loading the

plist, so let’s

let it continue

running...



is being sent to an

This exception tells you that an unknown selector (message)

coming from?

it

is

where

...so

tring

NSCFDictionary—specifically, isEqualToS

Loading the plist worked fine; no problems there. The error must be coming after that.

Let’s have the application continue running and see where it fails. Hit the Continue

button (or type continue in the console)...and there’s our exception again. Where is

this actually failing?



you are here 4  199

www.it-ebooks.info



CSI iPhone



Use the debugger to investigate

the crash

We can reliably get DrinkMixer to crash, and it doesn’t seem to be our

plist loading code. Xcode has suspended our application right before

iOS shuts it down, so we can use the debugger to see exactly what it was

trying to do before it crashed.

Switch back to the debugger and take a look at the stack on the left. This

is the call stack that led to the crash.



The stop button will

terminate your application.



Here’s the

stack at

the time

of the

crash. The

top 13

frames are

framework

code, but

frame 6 is

code we

wrote...



Trying to continue now

will just keep failing—

DrinkMixer has been

stopped by iOS.



And here’s the line that

caused the problem. See

what’s going on yet?

200   Chapter 5

www.it-ebooks.info



plists and modal views



So the exception talks about NSCF

Dictionary...maybe it has something to do

with the new drinks directions we uploaded

for the detail view?



You’re on to something there.

Let’s take a closer look.



Using what you’ve learned so far, figure out what’s going on!



The exception talks about NSCF Dictionary. What dictionary is it talking about? Where is it coming from?



Who’s sending messages to the dictionary? Why did we get an unrecognized selector?



you are here 4  201

www.it-ebooks.info



square peg, round hole



Using what you’ve learned so far, figure out what’s going on!



The exception talked about NSCF Dictionary. What dictionary is it talking about? Where is it coming from?



The dictionaries are coming from the plist! When we load the plist, we now have an array of

dictionaries instead of an array of strings.



Who’s sending messages to the dictionary? Why did we get an unrecognized selector?



Messages are being sent to the dictionary when we try to set the cell’s label text. It’s actually the

label sending it a message (see the next stack frame, it’s code in UILabel). It’s sending messages as

though the cell label text were a string. But now we’re assigning a dictionary to the label text!

/



}



// Configure the cell.

cell.textLabel.text = [self.drinks objectAtIndex:indexPath.row];

return cell;



RootViewController.m



We’re trying to stuff a dictionary into a string

Putting a dictionary into the text field of the label, which wants a string,

isn’t going to work. Our previous array was an array of strings, so that

code worked fine. Now that we have an array of dictionaries, we need to

figure out how to get the drink name value (a string) out of the dictionary,

and then assign that to the text label. If you take another look at the

DrinksDirections.plist, you’ll see that we have an array of dictionaries—

one for each drink. As we saw earlier, dictionaries store their values using

keys; they’re just a collection of key-value pairs. To get a value out, you

simply send the dictionary the objectForKey:@"key" message.



Instead of assigning the array

value right to the text label,

you’ll need to pull out the name

value from the appropriate

dictionary.

somelabel.text







Dictionary



name = Cupid’s

Cocktail

ingredients =

Cherry liqueur,

peach ...

directions =

Shake ingredients

and strain into...



202   Chapter 5

www.it-ebooks.info



we use the

For each drinkr, the name of

key name fo gredients

the drink, in s, and so on.

for ingredient



plists and modal views



Update your code to handle a

plist of dictionaries

Armed with the knowledge of how the dictionaries are

put together, we can use this information to populate

the detail view, too. If you give the detail view controller

the dictionary of the selected drink, it can populate the

view’s fields before the view is shown to the user.



Detail

View



Datasource



Each dictionary has

everything we need for

drink. We need to get tha

dictionary to the dataso at

urce

for the detail view.



View Controller



Go ahead and make the changes below to your app. After this, it should

know that you’re using an array of dictionaries, not strings—and the

detail view should have a reference to the drink it should display.



1



Change the way a table cell is configured.

In RootViewController.m, fix the cell’s textLabel.text property to use the

name value from the appropriate dictionary.



Don’t forget about the NSDictionary

documentation if you want to know more

about dictionaries.

2



Add a reference to a drink dictionary in the detail view.

In DrinkDetailViewController.h, add an NSDictionary* instance

variable named drink_ and the corresponding property declaration.



3



Add drink to the DrinkDetailViewController.m file.

Synthesize and dealloc the new dictionary reference.



detail view the

We’ll update the

the values in

e

controller to usin a minute...

new dictionary

you are here 4  203

www.it-ebooks.info



updating for dictionaries



Go through the code and make sure

that you’ve got everything right...



// Configure the cell.



cell.textLabel.text = [[self.drinks objectAtIndex:indexPath.row]







the

Use objectForKey to gearty.

ion

ct

di

name from the



objectForKey:@”name”];

return cell;



RootViewController.m

@private





UITextField *nameTextField_;







UITextView *directionsTextView_;



UITextView *ingredientsTextView_;







NSDictionary *drink_;







}



y*

Declare the NSDictionaarproperty

instance variable and mic, retain

with the usual nonato

attributes.



@property (nonatomic, retain) IBOutlet UITextField *nameTextField;



@property (nonatomic, retain) IBOutlet UITextView *ingredientsTextView;

@property (nonatomic, retain) IBOutlet UITextView *directionsTextView;



@property (nonatomic, retain) NSDictionary *drink;



This shouldn’t be an outlet since we won’t be

setting it through Interface Builder.



DrinkDetailViewController.h



Add drink to the synthesize line.



@synthesize drink=drink_, nameTextField=nameTextField_, ingredientsText

View=ingredientsTextView_, directionsTextView=directionsTextView_;







- (void)dealloc {















}



[nameTextField_ release];



[ingredientsTextView_ release];



our dictionary

reference here.



[directionsTextView_ release];

Release



[drink_ release];

[super dealloc];



@end

DrinkDetailViewController.m



204   Chapter 5

www.it-ebooks.info



plists and modal views



Test Drive

Now that we’ve told DrinkMixer how to deal with dictionaries, go ahead and build and run. Make

sure that the breakpoints are off!



It’s working again! Now that it’s not

crashing, it’s time to fill in the details.

you are here 4  205

www.it-ebooks.info



filling in the drink details



The Detail View needs data

Now that you’ve figured out how to deal with

dictionaries, it’s time to fill in the drink details.

But getting the details out of the array of

dictionaries to give to the datasource requires

another step.



Touch here

Nav

Controller



This is the information in

DrinksDirections.plist.



Datasource



The datasource

needs the

dictionary

information

for the

selected drink...



Detail View

Controller



Remember this? This is the

structure of the app.



How are we going to get the information from

DrinksDirections.plist into the Detail View?



206   Chapter 5

www.it-ebooks.info



plists and modal views



The other keys are key

Right now we’re just pulling the name of each drink into the app

using the name key. In order to populate the ingredients and

directions, we need to use the other keys. You could just type those

right into our code, but you’re a better developer than that, so let’s

pull them up into constants. The only thing left is getting the

proper dictionary to the detail view controller so it can pull the

information it needs. Go ahead and start setting everything up!



The View Controller needs direct access to the datasource,

and the easiest way to get to that data is going to mean

some quick code refactoring.

1



Organize your dictionary constants to avoid bugs.

Since we’re going to need the name, ingredients, and directions keys in the

View Controller, we should clean up the code to start using real constants.

Create a new file called DrinkConstants.h (right-click on the DrinkMixer

folder, then choose New File, and then choose Other and an empty file).

Add constants (#define’s) for NAME_KEY, INGREDIENTS_KEY and

DIRECTIONS_KEY. Import DrinkConstants.h into DrinkDetailViewController.m

and RootViewController.m. Finally, update where we use the @"name" key to the

new constant, NAME_KEY.



2



Set the detail View Controller’s drink property.

In the root View Controller, after you instantiate the detail View Controller when

a cell is tapped, you need to set the drink property on the new controller to the

selected drink.



3



Add code to the detail View Controller to populate values on the

UI controls.

Before the Detail View appears, the View Controller should use the drink

dictionary to set the contents of the name, ingredients, and directions components.

Don’t forget to use the constants you just set up!



you are here 4  207

www.it-ebooks.info



cleaning up with constants



Here’s all the added code to make the Detail View work.



1



Create DrinkConstants.h.



DrinkDetailViewController.m and RootViewController.m both need

#import "DrinkConstants.h".

We’re



changing the dictionary

keys to constants here...



Then add the constant to display the name:

// Configure the



cell.





cell.textLabel.text = [[self.drinks objectAtIndex:indexPath.row]

objectForKey:NAME_KEY];

return cell;



Change this value from

@“name”.



RootViewController.m



208   Chapter 5

www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 5. plists and Modal Views: Refining your app

Tải bản đầy đủ ngay(0 tr)

×