Chapter 13 Protocols
A formal protocol is a named list of methods.
You adopt a protocol by listing the protocol’s name in your class’s @interface declaration. When you do this, your class is said to conform to the protocol
Formal protocols are just like Java interfaces.
Declaring Protocols
@protocol NSCopying
- (id) copyWithZone: (NSZone *) zone;
@end
There are no instance variables introduced with a protocol.
MAKIN’ COPIES
When you create a shallow copy, you don’t duplicate the referred objects; your new copy simply points at the referred objects that already exist. NSArray’s copy method makes shallow copies. When you make a copy of an NSArray, your copy only duplicates the pointers to the referred objects, not the objects themselves. If you copy an NSArray that holds five NSStrings, you still end up with five strings running around your program, not ten. In that case, each object ends up with a pointer to each string.
A deep copy, on the other hand, makes duplicates of all the referred objects. If NSArray’s copy was a deep copy, you’d have ten strings floating around after the copy was made.
Copy Protocol
To be able to make a copy of an engine, the class needs to adopt the NSCopying protocol.
@interface Engine : NSObject <NSCopying>
@end // Engine
Because we’ve adopted the NSCopying protocol, we have to implement the copyWithZone: method. A zone is an
NSZone, which is a region of memory from which you can allocate memory.
Copy object that has no instance variable:
- (id) copyWithZone: (NSZone *) zone
{
Engine *engineCopy;
engineCopy = [[[self class] allocWithZone: zone] init];
return (engineCopy);
} // copyWithZone
Engine has no instance variables, so all we have to do is make a new engine object.
PS: If we use [Engine class], it only works for engine but not its subclass
Copy object that has instance variable:
@interface Tire : NSObject <NSCopying>
{
float pressure;
float treadDepth;
}
// ... methods
@end // Tire
- (id) copyWithZone: (NSZone *) zone
{
Tire *tireCopy;
tireCopy = [[[self class] allocWithZone: zone]
initWithPressure: pressure
treadDepth: treadDepth];
return (tireCopy);
} // copyWithZone
You don’t have to use the designated initializer for copying. If you want, you can use a plain init and use accessor methods to change attributes.
Copy subclass:
@interface AllWeatherRadial : Tire // protocol will be inherited
{
float rainHandling;
float snowHandling;
}
// ... methods
@end // AllWeatherRadial
- (id) copyWithZone: (NSZone *) zone
{
AllWeatherRadial *tireCopy;
tireCopy = [super copyWithZone: zone];
[tireCopy setRainHandling: rainHandling];
[tireCopy setSnowHandling: snowHandling];
return (tireCopy);
} // copyWithZone
Copy class that contains other objects:
// suppose car only contains engine
- (id) copyWithZone: (NSZone *) zone
{
Car *carCopy;
carCopy = [[[self class]
allocWithZone: zone]
init];
carCopy.name = self.name;
Engine *engineCopy;
engineCopy = [[engine copy] autorelease]; // we need to autorelease copy,alloc,new!
carCopy.engine = engineCopy;
}
Protocols and Data Types
You can specify protocol names in the data types you use for instance variables and method arguments. By doing this, you give the Objective-C compiler a little more information so it can help error-check your code.
- (void) setObjectValue: (id<NSCopying>) obj;
Objective-C 2.0 adds two new modifiers for protocols: @optional and @required.