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

head first iphone development a learners guide to creating objective c applications for the iphone 3 phần 3 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 (1.8 MB, 54 trang )

you are here 4 77
iPhone app patterns
#import “InstatwitViewController.h”
@implementation InstatwitViewController
@synthesize tweetPicker;

- (void)dealloc {
[tweetPicker release];
[activities release];
[feelings release];
[super dealloc];
}
@end
@ synthesize goes along with the
@property declaration in the .h
file. See Chapter 3 for more info
The last thing you need to do with
tweetPicker is release our reference to it -
another memory thing. We’ll come back to the
memory management in Chapter 3, we promise.
InstatwitViewController.m
and then add the implementation.
What’s next?
78 Chapter 2
connect the outlet to the code
Connect the picker to our outlet
You’re probably expecting this by now! Back into Interface Builder to
make the connection from the UIPickerView to the IBOutlet in our
view controller. Right-click on the UIPickerView, grab the circle next
to the “New Referencing Outlet,” and drop it on File’s Owner—our
InstatwitViewController sporting its new tweetPicker outlet.


When you click and drag up to
File’s Owner, you will be able to
connect it to the tweetPicker
outlet you just created.
What do you need to do now to get the data out of
the picker and into your Twitter message? Think
about the “Tweet it!” button press action and how
that will need to change
you are here 4 79
iPhone app patterns
Use our picker reference to pull
the selected values
Now all that’s left is to use our reference to the picker to get
the actual values Mike selects. We need to reimplement the
sendButtonTapped method to pull the values from the
picker. Looking at the UIPickerView documentation, the
method we need is selectedRowInComponent:. That
method returns a row value, which, just like before, we can
use as an index into our arrays.


- (IBAction) sendButtonTapped: (id) sender {
NSString* themessage = [NSString stringWithFormat:@”I’m %@ and feeling %@
about it.”,
[activities objectAtIndex:[tweetPicker selectedRowInComponent:0]],
[feelings objectAtIndex:[tweetPicker selectedRowInComponent:1]]];
NSLog(themessage);
NSLog(@”Tweet button tapped!”);
}
Pull this log message out and put in one to see

what the final Twitter message will be.
Here’s the implementation for our callback. We
need to create a string and fill in the values from
the picker. the “%@” in the string format get
replaced with the values we pass in.
To figure out what Mike chose on the
picker, we need to ask the picker what row
is selected, and get the corresponding string
from our arrays.
We’re just going to log this message to the console so we can see
the string we’re building, and then we’ll send this to Twitter in
just a minute. Let’s make sure we implemented this correctly first
before tweeting to the whole world
InstatwitViewController.m
We want to build a new string with the full tweet text
in it, so we’ll use NSString’s stringWithFormat method to
create a templated string. There are lots of other options
you could use with a string format, like characters, integers,
etc., but for now we just need to insert the two selected
strings, so we’ll use %@.
80 Chapter 2
ready to tweet
Test Drive
OK, try it out. You should get a convincing tweet in the
console:
Once we add the Twitter info, this is
what will actually show up in your feed
as a tweet.
All that’s left is to talk to Twitter—
we’ll help you with that.

you are here 4 81
iPhone app patterns
Ready Bake
Code
//TWITTER BLACK MAGIC
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL
URLWithString:@”http://YOUR_TWITTER_USERNAME:/
statuses/update.xml”]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[theRequest setHTTPMethod:@”POST”];
[theRequest setHTTPBody:[[NSString stringWithFormat:@”status=%@”,
themessage] dataUsingEncoding:NSASCIIStringEncoding]];
NSURLResponse* response;
NSError* error;
NSData* result = [NSURLConnection sendSynchronousRequest:theRequest
returningResponse:&response error:&error];
NSLog(@”%@”, [[[NSString alloc] initWithData:result
encoding:NSASCIIStringEncoding] autorelease]);
// END TWITTER BLACK MAGIC
To post to Twitter, we’re going to use their API. Rather than
go into a Twitter API tutorial, we’ll give you the code you
need to tweet the string. Type the code you see below into the
InstatwitViewController.m, just below the NSLog with the
Twitter message in the sendButtonTapped method.
Your username and password
need to go in here.
If you don’t have a Twitter account,
just go get one!
Just go to twitter.com and register. Once

you do that, you can enter your username
and password, and this will work like a charm.
After adding that code, you can just save, build and go. It will
now show up on your Twitter feed. Go ahead, try it out!
InstatwitViewController.m
82 Chapter 2
mike’s feeling great about your app
That is great! Now, Renee is happy and feels
included and I don’t actually have to talk out loud
about my feelings. At all. Ever.
you are here 4 83
iPhone app patterns
iPhonecross
Flex your vocab skills with this crossword.
Untitled Puzzle
Header Info 1
Header Info 2
etc
1 2
3 4
5
6
7 8
9
10
11
Across
3. This typically handles the information itself in the app.
6. This is the document Apple uses to evaluate apps for
the App Store.

7. You see this listed in the view and it controls the view.
9. This component allows for controlled input from several
selections.
10. This type of app is typically one screen, and gives you the
basics with minimal interaction.
11. These define to which messages the datasource and
delegate respond.
Down
1. This typically contains the logic that controls the flow of
information in an app.
2. The best way to figure out what protocols you need to worry
about is to check the ____________.
4. This app type typically involves hierarchical data.
5. This app type is mostly custom controllers and graphics.
8. The other name for an *.xib file.
84 Chapter 2
more app types
We’ve listed a couple of descriptions of a some different
apps. Using the app description, sketch out a rough view
and answer the questions about each one.
Generic giant button app
There are several of these currently up for sale
on the app store. This app consists of pushing
a big button and getting some noise out of
your iPhone.
1
What type of app is this?
What are the main concerns in the HIG
about this app type?
Book inventory app

This app’s mission is to keep a list of the books
in your library, along with a quick blurb of
what it’s about and the author.
2
What type of app is this?
What are the main concerns in the HIG
about this app type?
you are here 4 85
iPhone app patterns
iPhonecross Solution
Flex your vocab skills with this crossword.
Untitled Puzzle
Header Info 1
Header Info 2
etc
D
1
D
2
D
3
A T A S O U R C E P
4
O
L R C
I
5
E O U
H
6

U M A N I N T E R F A C E G U I D E M
M A U E
F
7
I L E S O W N E R N
8
T C N
R P
9
I C K E R T T
S B I A
U
10
T I L I T Y F V T
V I I I
E L P
11
R O T O C O L S
E Y N
Across
3. This typically handles the information itself in the app.
[DATASOURCE]
6. This is the document apple uses to evaluate apps for the
App Store. [HUMANINTERFACEGUIDE]
7. You see this listed in the view and it controls the view.
[FILESOWNER]
9. This component allows for controlled input from several
selections. [PICKER]
10. This type of app is typically one screen, and gives you the
basics with minimal interaction. [UTILITY]

11. These define to which messages the datasource and
delegate respond. [PROTOCOLS]
Down
1. This typically contains the logic that controls the flow of
information in an app. [DELEGATE]
2. The best way to figure out what protocols you need to worry
about is to check the ____________. [DOCUMENTATION]
4. This app type typically involves hierarchical data.
[PRODUCTIVITY]
5. This app type is mostly custom controllers and graphics.
[IMMERSIVE]
8. The other name for an *.xib file. [NIBFILE]
86 Chapter 2
exercise solution
We’ve listed a couple of descriptions of a some different apps.
Using the app description, sketch out a rough view and answer
the questions about each one.
Generic giant button app
There are several of these currently up for sale
on the app store. This app consists of pushing
a big button and getting some noise out of
your iPhone.
1
What type of app is this?
What are the main concerns in the HIG
about this app type?
Book inventory app.
This app’s mission is to keep a list of the books
in your library, along with a quick blurb of
what it’s about and the author.

2
What type of app is this?
What are the main concerns in the HIG
about this app type?
Bug button
that you push
Just one view
An immersive app
The big thing Apple cares about is that
controls “provide an internally consistent
experience.” So everything can be custom, it
needs to focused and well organized.
A productivity app
The HIG has many more specific rules about
this app type, because you’ll be using standard
controls. EACH control needs to be checked
out for proper usage.
Another view for details, need to figure
out how to get to it
Book list
Some navigation stuff here
you are here 4 87
iPhone app patterns
Your iPhone Toolbox
You’ve got Chapter 2 under
your belt and now you’ve
added protocols, delegates, and
datasources to your toolbox. For a
complete list of tooltips in the book,
go to />iphonedev.

CHAPTER 2
 The picker needs a delegate and data-
source to work.
 In a picker, each dial is a component.
 In a picker, each item is a row.
 Protocols define the messages your class
must realize—some of them might be
optional.
Protocols
Define the messages your
datasource and delegate must
respond to.
Are declared in the header (.h)
file.
Some of them might be optional.
Datasource
Provides the bridge between the
control and the data it needs to
show.
Works with databases, plists,
images, and other general info
that your app will need to display.
Can be the same object as a
delegate, but has its own specific
protocols.
Delegate
Responsible for the behavior of a
UI element
Contains the logic that controls
the flow of information, like

saving or displaying data, and
which view is seen when.
Can be in same object as the
datasource, but has its own
specific protocols.
88 Chapter 2
renee is getting suspicious
This is Renee, Mike’s
girlfriend
It’s so great that Mike and I are
communicating now! But I’ve noticed that
Mike’s starting to sound like he’s in a rut, saying
the same thing over and over again! Is there
something we need to talk about?
Sounds like Mike is going
to need some modifications
to InstaTwit to keep his
relationship on solid ground
this is a new chapter 89
I know these are letters and
all, but I have no idea what
you’re saying
objective-c for the iPhone
3
Twitter needs variety
We did a lot in chapter 2, but what language was that?
Parts of the code you’ve been writing might look familiar, but it’s time you got a sense of
what’s really going on under the hood. The iPhone SDK comes with great tools that mean
that you don’t need to write code for everything, but you can’t write entire apps without
learning something about the underlying language, including properties, message passing,

and memory management. Unless you work that out, all your apps will be just default
widgets! And you want more than just widgets, right?
90 Chapter 3
renee wants more
InstaTwit was working great, and is so easy to use!
But I think Renee is on to me. She said I sound like
I’m in a rut. I need to be able to add to my tweets
or this isn’t going to work much longer.
Renee is catching on
Mike has been diligently using InstaTwit to communicate his feelings, but his
girlfriend is starting to think something weird is going on. Even for Mike, who
is a guy who likes his routines, his tweets are starting to sound suspicious.
We need to make some adjustments
to our InstaTwit design.
Take a look at the various UI controls available in
Interface Builder, and think about what would be a
quick and easy way for Mike to add to his tweets.
you are here 4 91
objective-c for the iPhone
We’ll put the
text field in
here
Scoot this
stuff down a
little
Code Magnets
Using what you know from adding the picker and the button, match the
magnet with the method or file that you’ll need to edit to add the text field.
Add an IBOutlet and @property
declaration for the UITextField

Add [notesfield release]
Link the UITextField
to the IBOutlet
Add UITextField
to the view
Add
notesField to
@synthesize

1

2

3

4

5
to InstatwitViewController.h.
to the top of
InstatwitViewController.m.
to the dealloc in
InstatwitViewController.m.
using Interface Builder.
to the property created in step
#1, using Interface Builder.
Create a delegate and
datasource for the notesField
Add an IBAction for
the UITextField

Make room for custom input
It’s nothing fancy, but Mike could add a little personal flavor to his
tweets with a text field at the start. It means he’ll need to do some
typing, but in the end his tweets will be more unique.
92 Chapter 3


IBOutlet UIPickerView *tweetPicker;

IBOutlet UITextField *notesField;
NSArray* activities;
NSArray* feelings;
}
@property (nonatomic, retain) UIPickerView* tweetPicker;
@property (nonatomic, retain) UITextField* notesField;
design magnets solution
Design Magnets Solution
Using what you know from adding the picker and the button, match the
magnet with the method or file that you’ll need to edit to add the text field.
Add an IBOutlet and @property
declaration for the UITextField

1
to InstatwitViewController.h.
What we need is a UITextField
. To implement the new
field, we need to declare a class member (with
IBOutlet

so Interface Builder sees it) and add a property that we’ll

call
notesField
.
Wait a minute. We keep adding
code to this .h file, but I still don’t
know what a .h file really does!
What gives?
A .h file is a header file.
It’s where you declare the interface and methods for a class. All
of the classes we’ve used so far, like UITextField, NSString, and
NSArray, have header files you can look through. Take a minute to
look through a couple and start thinking about what is happening
in those files.
Beware of private framework headers
Sometimes you’ll come across a really
tempting method that’s not defined in the Apple
Documentation. Using undocumented APIs will
get your app rejected from the iTunes store.
InstatwitViewController.h
you are here 4 93
objective-c for the iPhone
- (IBAction) sendButtonTapped: (id) sender;
Here’s our current InstatwitViewController.h file. Fill in the
blanks and explain what each line does.
#import <UIKit/UIKit.h>
@interface InstatwitViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate> {
IBOutlet UIPickerView *tweetPicker;
IBOutlet UITextField *notesField;
NSArray* activities;

NSArray* feelings;
}
@property (nonatomic, retain) UIPickerView* tweetPicker;
@property (nonatomic, retain) UITextField* notesField;
- (IBAction) sendButtonTapped: (id) sender;
- (IBAction) textFieldDoneEditing:(id) sender;
@end
Header files describe the interface to your class
In Objective-C, classes are defined with interfaces in the header file. It’s where you declare if your
class inherits from anything, as well as your class’ fields, properties, and methods.
IBOutlet UIPickerView *tweetPicker;
@interface InstatwitViewController :
UIViewController
InstatwitViewController.h
Interfaces, class fields,
methods, and properties
InstatwitViewController.m
InstatwitViewController.h
94 Chapter 3
sharpen solution
Here’s our current InstatwitViewController.h file. Fill in the blanks
and explain what each line does.
#import <UIKit/UIKit.h>
@interface InstatwitViewController :
UIViewController <UIPickerViewDataSource,
UIPickerViewDelegate> {

IBOutlet UIPickerView *tweetPicker;
IBOutlet UITextField *notesField;
NSArray* activities;

NSArray* feelings;
}
# import incorporates another file (almost always a header
file) into this file when it’s compiled. It’s used to pull in classes,
constants, etc. from other files.
This is where we can declare fields of our class.
Here’s our inheritances and interfaces.
It’s almost identical to C’s #include,
except that it automatically prevents
including the same header multiple
times (so no more #ifndef
MY_HEADER).
@interface indicates you’re
going to declare a class.
Next comes the class name, and
if it inherits from something
then a colon and the super
class’s name.
Any protocols you implement go in
angle brackets separated by commas.
Protocols are like Java interfaces or
pure virtual classes in C++, and a class
can realize as many as you want.
IBOutlet allows Interface Builder to
recognize fields that you can attach to
controls (like our notes field in InstaTwit).
The syntax for fields is just like in C++:
Basic types like int and float are used
as is; pointer types use an asterisk. By
default, all fields are given protected

access, but you can change that with
@private or @public sections similar to
C++.
Objective-C doesn’t support
multiple inheritance
InstatwitViewController.h
you are here 4 95
objective-c for the iPhone
@property (nonatomic, retain) UIPickerView* tweetPicker;
@property (nonatomic, retain) UITextField* notesField;
- (IBAction) sendButtonTapped: (id) sender;
- (IBAction) textFieldDoneEditing:(id) sender;
@end
Once you’ve closed the field section of your interface, you
can declare properties. @property tells Objective-C to
autogenerate getter and setter methods for you.
The @property keyword tells the
compiler this is a property that will be
backed by getter and (maybe) setter
methods.
These are property attributes; we’ll
talk more about these shortly
Here’s our type and property
name, just like the field in
the class.
These are the method declarations.
@end: ends your class interface declaration.
The minus sign means it’s an instance
method (a + means it’s static). All
methods in Objective-C are public.

IBAction lets Interface
Builder identify methods
that can be attached to
events.
IBAction method signatures must
take one argument of type id, which
is like a void * in C++ or Object
reference in Java.
InstatwitViewController.h
96 Chapter 3
@synthesize tweetPicker, notesField;
magnets solution
Design Magnets Solution (Continued)
Using what you know from adding the picker and the button, match the
magnet with the method or file that you’ll need to edit to add the text field.
Add notesField
to @synthesize

2
to the top of
InstatwitViewController.m.
Here you synthesize the accessor methods
from @property. You can create a new
@synthesize line or just add it after a
comma on the line that’s already there.
OK, so if we declared a property
in the .h file, then adding @synthesize
in the .m file must auto-generate some
code, right?
Yes! It generates the getter and setter methods.

Using @property lets the compiler know we have a property,
but that’s not enough. Using the @synthesize keyword in the
implementation files, we can have the compiler auto-generate the
setter and getter method we talked about earlier. The compiler will
generate a getter, and, if it’s a readwrite property, a setter and
implement it based on the @property attributes declared in the .h
file. So what do the different @property attributes do ?
Back in that design we
were working on

I B O u t l e t UIPickerView *tweetPicker;

IBOutlet UITextField *notesField;
NSArray* activities;
NSArray* feelings;
}
@property (nonatomic, retain) UIPickerView* tweetPicker;
@property (nonatomic, retain) UITextField* notesField;
Add an IBOutlet and @property
declaration for the UITextField

1
to InstatwitViewController.h.
InstatwitViewController.h
InstatwitViewController.m
you are here 4 97
objective-c for the iPhone
When you want the property to be modifiable by
people. The compiler will generate a getter and a
setter for you. This is the default.

readonly
Below is a list of the most commonly used property attributes and
definitions. Match each attribute with its definition.
assign
retain
copy
readwrite
When you’re dealing with basic types, like ints, floats,
etc. The compiler just creates a setter with a simple
myField = value statement. This is the default, but
not usually what you want.
When you’re dealing with object values. The compiler
will retain the value you pass in (we’ll talk more about
retaining in a minute) and release the old value when a
new one comes in.
When you don’t want people modifying the property.
You can still change the field value backing the
property, but the compiler won’t generate a setter.
When you want to hold onto a copy of some value
instead of the value itself; for example, if you want
to hold onto an array and don’t want people to be able
to change its contents after they set it. This sends a
copy message to the value passed in then retains that.
98 Chapter 3
who does what solution
When you want the property to be modifiable by
people. The compiler will generate a getter and a
setter for you. This is the default.
readonly
assign

retain
copy
readwrite
When you’re dealing with basic types, like ints, floats,
etc. The compiler just creates a setter with a simple
myField = value statement. This is the default, but
not usually what you want.
When you’re dealing with object values. The compiler
will retain the value you pass in (we’ll talk more about
retaining in a minute) and release the old value when a
new one comes in.
When you don’t want people modifying the property.
You can still change the field value backing the
property, but the compiler won’t generate a setter.
When you want to hold onto a copy of some value
instead of the value itself; for example, if you want
to hold onto an array and don’t want people to be able
to change its contents after they set it. This sends a
copy message to the value passed in then retains that.
SOlUTion
Q:
How does the compiler know what field to use to hold the
property value?
A: By default, the compiler assumes the property name is the
same as the field name. In reality, it doesn’t have to be. You can
specify the field to use to back a property when you @synthesize it
like this: @synthesize secretString=_superSecretField;.
Q:
What about that nonatomic keyword?
A: By default, generated accessors are multithread safe and use

mutexes when changing a property value. These are considered
atomic. However, if your class isn’t being used by multiple threads,
that’s a waste. You can tell the compiler to skip the whole mutex thing
by declaring your property as nonatomic.
Below is a list of the most commonly used property attributes and
definitions. Match each attribute with its definition.
you are here 4 99
objective-c for the iPhone
Auto-generated accessors also handle memory
management
Objective-C on the iPhone doesn’t have a garbage collector, so you have to use reference counting.
That involves keeping up with how many references there are to an object, and only freeing it up
when the count drops to zero (it’s no longer being used). When you use properties, the compiler
handles it for us. The properties we’ve declared so far have all used the retain attribute. When the
compiler generates a setter for that property, it will properly handle memory management for us,
like this:
@property (nonatomic, retain) NSString* secretString;
@synthesize secretString
- (NSString*) secretString {
return secretString;
}
- (void) setSecretString: (NSString*) newValue {
if (newValue != secretString) {
[secretString release];
secretString = [newValue retain];
}
}
Here the compiler just returns
the value, nothing exciting.
Since we didn’t say the property

is readonly, the compiler will
generate a setter for us.
Since we used the retain keyword, the
generated setter checks to make sure
the new value is different, then does
a release on the old value and a retain
on the new one.
Nonatomic means no
locks
Retain says we’re using an object type and we want
to hang onto the object passed to the setter.
This would be in your
@implementation
section.
Write the code that Objective-C generates for each property
declaration below.
1. @property (nonatomic, readonly) NSString* myField
2. @property (nonatomic, retain) NSString* myField
3. @property (nonatomic, assign) NSString* myField
100 Chapter 3
sharpen solution
1. @property (nonatomic, readonly) NSString* myField
2. @property (nonatomic, retain) NSString* myField
3. @property (nonatomic, assign) NSString* myField
- (NSString*) myField {
return myField;
}
- (void) setMyField: (NSString*)
newValue {
if (newValue !=myField) {

[myField release];
myField = [newValue retain];
}
}
- (NSString*) myField {
return myField;
}
- (NSString*) myField {
return myField;
}
- (void) setMyField: (NSString*) newValue
{
myField = newValue;
}
Be careful with this one NSStrings are
reference counted objects, so while this
will technically work, having an assign
property for an NSString is probably a
bad idea.
However, for basic types like booleans and floats,
you can’t do reference counting. Assignment is
almost always what you want.
Below is the code that the compiler will generate for each
property.
you are here 4 101
objective-c for the iPhone
I bet that release just lets go of
the memory that your properties
use up, right?
Objective-C can automatically release references, too.

In addition to retain and release, Objective-C has the concept of an
autorelease pool. This is basically an array of objects that the runtime
will call release on after it’s finished processing the current event. To put
something in the autorelease pool, you simply send it the autorelease
message:
[aString autorelease];
It will still have the same retain count, but after the current event loop
finishes, it will be sent a release. You won’t want to use this all the time
because it’s not nearly as efficient and has some performance overhead. It’s
not a bad thing to use, but it’s better to explicitly retain and release when
you can.
You must release objects you create with alloc, new, copy, or mutableCopy.
If you create an object with alloc, new, copy, or mutableCopy, it will have a retain count of 1
and you’re responsible for sending a release when you’re done with the object. You can also
put the object in the autorelease pool if you want the system to handle sending a release later.
1
Consider everything else to have a retain count of 1 and in the autorelease
pool.
If you get an object by any other means (string formatters, array initializers, etc.) you should
treat the object as having a retain count of 1 and put it in the autorelease pool. This means
that if you want to hang onto that object outside of the method that got the object, you’ll
need to send it a retain (and a corresponding release later).
2
To keep your memory straight, you need to
remember just two things
Memory management can get pretty hairy in larger apps, so Apple has a couple of
rules established to keep track of who’s in charge of releasing and retaining when.
Get it? Memory,
remember?

×