In the interest of getting started quickly, here's a quick tour of new features in Objective-C 2.0 which will probably affect about 80% of the work you do. We'll look at properties, dot syntax, fast enumeration, and garbage collection.
Properties
Properties are a generic way of declaring the data a class provides. In a Movie class, the properties would be things like title, studio, and yearReleased. Here's what the header for the Movie class looks like in Objective-C 1.x:
@interface Movie : NSObject {
NSString* title;
NSString* studio;
int yearReleased;
}
+ (id)movie;
- (NSString*)title;
- (void)setTitle:(NSString*)aValue;
- (NSString*)studio;
- (void)setStudio:(NSString*)aValue;
- (int)yearReleased;
- (void)setYearReleased:(int)aValue;
- (NSString*)summary;
@end
Here's how it looks using Objective-C 2.0 and the new Leopard NSInteger type:
@interface Movie : NSObject {
NSString* title;
NSString* studio;
NSInteger yearReleased;
}
+ (id)movie;
@property (copy) NSString* title;
@property (copy) NSString* studio;
@property (assign) NSInteger yearReleased;
@property (readonly) NSString* summary;
@end
Notice that not everything is a property. There's a class method for generating new objects called +movie. There's no way (or need) to declare this as a property. The format is:
@property (
The most-commonly used parameters are copy/retain/assign. You choose one to specify how the setter will be generated for the property. Many Objective-C objects are best used with retain, but since these are strings, we'll use copy.
The assign keyword will generate a setter which assigns the value to the instance variable directly, rather than copying or retaining it. This is best for primitive types like NSInteger and CGFloat, or objects you don't directly own, such as delegates. Keep in mind retain and assign are basically interchangeable when garbage collection is enabled.
The readonly keyword means a setter will not be generated, so it should not be used in combination with any of copy/retain/assign. We're declaring summary as readonly because there's no instance variable for it. Instead, we generate the contents for it on the fly.
Let's take a look at the implementation of this class in Objective-C 1.x:
@implementation Movie
+ (id)movie {
return [[[Movie alloc] init] autorelease];
}
- (NSString*)title {
return title;
}
- (void)setTitle:(NSString*)aValue {
[title autorelease];
title = [aValue copy];
}
- (NSString*)studio {
return studio;
}
- (void)setStudio:(NSString*)aValue {
[studio autorelease];
studio = [aValue copy];
}
- (int)yearReleased {
return yearReleased;
}
- (void)setYearReleased:(int)aValue {
yearReleased = aValue;
}
- (NSString*)summary {
NSNumber* yearAsObject;
yearAsObject = [NSNumber numberWithInt:[self yearReleased]];
return [NSString stringWithFormat:@"%@ by %@, released in %@",
[self title], [self studio], yearAsObject];
}
@end
And here's the Objective-C 2.0 version (with garbage collection enabled):
@implementation Movie
@synthesize title;
@synthesize studio;
@synthesize yearReleased;
+ (id)movie
{
return [[Movie alloc] init];
}
- (NSString*)summary
{
NSNumber* yearAsObject;
yearAsObject = [NSNumber numberWithInteger:self.yearReleased];
return [NSString stringWithFormat:@"%@ by %@. Released in %@.",
self.title, self.studio, yearAsObject];
}
@end
The @synthesize directive generates accessor methods for us and garbage collection means +movie doesn't have to autorelease the object it returns. In addition, we use self.title and self.studio instead of [self title] and [self studio].
Let's see how this looks from the perspective of a client of the Movie class:
Movie* newMovie = [Movie movie];
newMovie.title = @"The Incredibles";
newMovie.studio = @"Pixar";
newMovie.yearReleased = 2004;
NSLog (@"Movie summary: %@", newMovie.summary);
This, of course, prints the following in the console:
Movie summary: The Incredibles, by Pixar. Released in 2004.
You can use either of the two accessor forms in Objective-C 2.0. You're not required to use dot syntax to access properties. You can also use the dot syntax on classes which don't explicitly define properties. For example:
NSString* newString = [textField stringValue];
NSString* newString = textField.stringValue;
The difference between @property and @synthesize might seem a bit unclear at first. Think of @property as declaring a property exists. The @synthesize directive actually implements code for the accessors, if necessary.
Note: By default, synthesized accessors are atomic in that the getter is guaranteed to return a valid value even with multiple active threads. There's no cost for this if garbage collection is enabled. You can disable this behavior with the keyword nonatomic.
Fast Enumeration
In Objective-C 1.x, your main options for loops were the standard for and while loops from C, and NSEnumerators. In Objective-C 2.0, you can use fast enumeration, which looks like this:
NSArray* allMovies = self.movies;
for ( Movie* oneMovie in allMovies ) {
NSLog ( @"%@\n", oneMovie.summary );
}
It's a much simpler syntax, much faster than a for loop, and much safer since trying to modify the collection while it's being enumerated will cause an exception.
Garbage Collection
There's not much to say about garbage collection in a introductory-level tutorial. For the most part, it should "just work" in simple cases. Once you enable it, retain, release, autorelease and the other memory management methods have no effect. The copy and mutableCopy messages, of course, still copy the value of the object.
Garbage Collection is off by default. You enable it by double-clicking a target in your project and changing the "Objective-C Garbage Collection" setting to "Required":
Xcode Enable Garbage Collection
Garbage collection does not collect CF-style objects, such as CGImageRef, and you obviously still need to handle manually-allocated memory with malloc() and free(). There are a number of keywords you can use to get finer-grained control, such as specifying weak references. Those details are outside of the scope of this tutorial.
Keep in mind that the dealloc method is not called when garbage collected is on, but you can implement -finalize for some (though not all) of the same cases. Garbage collection eliminates retain cycles (objects which retain each other and are never released).
A Few Tips
When using properties with the dot syntax, prefix the name with self to use the accessor:
// direct access
value = studio;
studio = value;
// uses accessor methods, sends KVO notifications
self.studio = value;
value = self.studio
Even if you have garbage collection enabled, you should still use the accessor methods in most cases because Key-Value Observing, and Cocoa Bindings depend on these methods being called to synchronize changes across objects.
The NSInteger, NSUInteger and CGFloat types are architecture-safe versions of int, unsigned int and float/double. They'll shield you from the underlying processor-specific issues. If you're targeting Leopard, you should use these instead of the ANSI C alternatives. NSNumber has new methods for these types:
- (id)initWithInteger:(NSInteger)value;
- (id)initWithUnsignedInteger:(NSUInteger)value;
- (NSInteger)integerValue;
- (NSUInteger)unsignedIntegerValue;
+ (NSNumber *)numberWithInteger:(NSInteger)value;
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
If you need to access a C struct in an Objective-C object, you may need to explicitly use brackets:
// "bounds" is a C struct. may be too ambiguous for the compiler
CGFloat value = self.bounds.origin.y;
// works reliably
CGFloat value = [self bounds].origin.y
Wrap-up
There's a lot more ground to cover, but this should give you a good start. We can look at more advanced topics in future tutorials. The 64-bit runtime has some features that the 32-bit version does not, such as the ability to synthesize instance variables. All of the hardware Apple currently ships is 64-bit, but we're a ways off from 64-bit being a majority of the installed base.
Remember that all of the new features in Objective-C 2.0 are optional. Aside from some lower-level runtime functions and hacks, anything that was valid code in Objective 1.x is valid in 2.0, as well.
For more information, see the Objective-C 2.0 Overview at Apple Developer Connection.
Posted by
Jarod Yv
at
9:36:00 PM
Subscribe to:
Post Comments (Atom)
0 comments:
Post a Comment