属性:
苹果公司在Objective-C 2.0中引进了属性(property)这个技术,它组合了新的预编译指令和属性访问器语法。新的属性功能明显减少了必须编写的冗余代码量。
注意:
在Objective-C 2.0的特性只适用于Mac OS X 10.5以上版本,如果必须支持旧的版本,则就不能使用属性功能了(至少目前是这样)另外,属性在ios开发中被广泛使用。
具体使用如下,重构子类AllWeatherRadial声明及实现:
声明部分:
#import "Tire.h"
@interface AllWealtherRadial : Tire
@property float rainHandling;
@property float snowHandling;
@end // AllWeatherRadial
实现部分:
#import "AllWealtherRadial.h"
@implementation AllWealtherRadial
@synthesize rainHandling;
@synthesize snowHandling;
- (id) initWithPressure:(float)p treadDepth:(float)td
{
if(self = [super initWithPressure:p treadDepth:td])
{
pressure = 23.7;
treadDepth = 42.5;
}
return (self);
}
- (NSString *) description
{
NSString *desc;
desc = [[NSString alloc] initWithFormat:
@"AllWeatherRadial: %.1f / %.1f / %.1f / %.1f ",
[self pressure],[self treadDepth],
[self rainHandling],[self snowHandling]];
return (desc);
} // description
@end // tire
注意:
上面使用了属性@synthesize来替代原始的setter和getter自定义访问方法,而使用关键字@property来生成属性变量。另外,在Xcode 4.5以后版本中,可以不必使用关键字@synthesize了。
属性拓展:
在这里对Car类添加一个新的变量name,它代表着汽车的名字,代码如下所示:
声明部分:
#import <Cocoa/Cocoa.h>
@class Engine;
@class Tire;
@interface Car:NSObject
{
NSString *name;
Engine *engine;
NSMutableArray *tires;
}
@property (copy) NSString *name;
@property (retain) Engine *engine;
- (Tire *) tireAtIndex:(int) index;
- (void) setTire:(Tire *) tire atIndex:(int)index;
- (void) print;
@end // car
实现部分:
#import "Car.h"
#import "Engine.h"
#import "Tire.h"
@implementation Car
- (id) init
{
if(self == [super init])
{
name = [[NSString alloc] initWithString:@"Car"];
engine = [Engine alloc];
tires = [[NSMutableArray alloc] init];
for(int i = 0;i < 4;i ++)
{
[tires addObject:[NSNull null]];
}
}
return (self);
}
@synthesize name;
@synthesize engine;
- (Tire *) tireAtIndex:(int)index
{
Tire *tire;
tire = [tires objectAtIndex:index];
return (tire);
}
- (void) setTire:(Tire *)tire atIndex:(int)index
{
[tires replaceObjectAtIndex: index withObject:tire];
}
- (void) dealloc
{
[name release];
[tires release];
[engine release];
[super dealloc];
}
- (void) print
{
NSLog(@"%@ has:",name);
for(int i =0;i < 4;i ++)
{
NSLog(@"%@",[self tireAtIndex:i]);
}
NSLog(@"%@",engine);
@end // car
上面的代码,使用了属性替代了原来的setter和getter方法,同时对引用的对象使用了保留和复制特性:
@property (copy) NSString *name;
@property (retain) Engine *engine;
名称的使用:
我们知道常用的做法是保持实例变量名与属性变量名相同,但有的时候,我们希望实例变量是一个名字,而公开的属性却是另一个名字。具体如下,修改Car类中的实例变量name为appellation,同时修改@synthesize指定新名字与老名字的关联即可:
声明部分:
@class Engine;
@class Tire;
@interface Car:NSObject
{
NSString *appellation;
Engine *engine;
NSMutableArray *tires;
}
@property (copy) NSString *name;
@property (retain) Engine *engine;
- (Tire *) tireAtIndex:(int) index;
- (void) setTire:(Tire *) tire atIndex:(int)index;
- (void) print;
@end // car
实现部分:
#import "Car.h"
#import "Engine.h"
#import "Tire.h"
@implementation Car
- (id) init
{
if(self == [super init]) {
self.name = [[NSString alloc] initWithString:@"Car"];
engine = [Engine alloc];
tires = [[NSMutableArray alloc] init];
for(int i = 0;i < 4;i ++)
{
[tires addObject:[NSNull null]];
}
}
return (self);
}
@synthesize name = appellation;
@synthesize engine;
- (Tire *) tireAtIndex:(int)index
{
Tire *tire;
tire = [tires objectAtIndex:index];
return (tire);
}
- (void) setTire:(Tire *)tire atIndex:(int)index
{
[tires replaceObjectAtIndex: index withObject:tire];
}
- (void) dealloc
{
[self.name release];
[tires release];
[engine release];
[super dealloc];
}
- (void) print
{
NSLog(@"%@ has:",self.name);
for(int i =0;i < 4;i ++)
{
NSLog(@"%@",[self tireAtIndex:i]);
}
NSLog(@"%@",engine);
@end // car
很明显,在实现代码中,我们将name和appellation关联了起来:
@synthesize name = appellation;
实际上,编译器依然创建setName和name方法,但实际上用的却是新的appellation实例变量,编译时会遇到问题,所以解决的办法是将实例变量的直接访问改为访问方法,如:self.name,这种做法就可以消除编译器歧义,使其知道使用访问方式获得变量。
只读属性使用:
我们知道对象的属性是可变的,即可以读取也可以修改的。我们可以使用readwrite特性。对象默认的属性为readwrite,一般不会用到它,但为了表明自己的用意,建议填上这个属性特性。具体如下,我们修改Car类,让它支持属性特点实现:
@property (readwrite, copy) NSString *name;
@property (readwrite, retain) Engine *engine;
注意:
A、我们有时会使用属性readonly,如果修改了该属性对象,那么编译器就会报错。
B、如果我们不想编译器自动生成变量、setter及getter,那么可以使用@dynamic来修饰实例变量。
C、特性不是万能的,从之前的例子中可以知道,我们并没有提供转换tire对象的访问方法以支持属性。
- (Tire *) tireAtIndex:(int)index
{
Tire *tire;
tire = [tires objectAtIndex:index];
return (tire);
}
- (void) setTire:(Tire *)tire atIndex:(int)index
{
[tires replaceObjectAtIndex: index withObject:tire];
}
因为这些方法不能适应属性所覆盖的较小范围。属性只支持替代setter及getter方法。
好了,属性的使用就总结到这里。
/**
* 技术交流群:179914858
*/