深刻理解属性、getter及setter

来源:互联网 发布:网络扶贫行动计划 编辑:程序博客网 时间:2024/04/29 23:41

原文:http://iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-and-properties-for-the-newbie.html

 对于有Mac开发经验的iPhone开发者,可能对O-C的注解“@property”已经习以为常了。但对于从其他开发平台(Java或者Symbian)迁移过来的iPhone开发者,“@property”仍然有点麻烦。为了使这些人不再犯我一样的错误,本文简单探讨了变量及属性,以及它们所采用的内存管理。

首先来看一个简单类:

 //MyClass.h file

@interface MyClass: NSObject
{
    NSString *text;
}

-(void) init;
-(void) logText;
@end

//MyClass.m file
@implementation MyClass

- (void)init
{
    text = @\"sometext\";
}

- (void)logText
{
   NSLog(@\"%@\", text);
}
@end


这个类十分简单。它唯一的成员就是text,一个NSString。text变量在init方法中初始化,在logText方法中被引用。
就目前而言,text变量中存储的是常量值,我们无须关心它的内存管理。但在真正的程序中,我们可能会想在运行时改变text的值,因此需要为它设计getter和setter方法:


//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
}

-(void) init;
-(void) logText;
-(NSString*) text;
-(void) setText:(NSString *)textValue;
@end

//MyClass.m file
@implementation MyClass

- (void)init
{
    text = @\"sometext\";
}

- (void)logText
{
   NSLog(@\"%@\", text);
}

-(NSString*) text
{
    return text;
}

-(void) setText:(NSString *)textValue
{
    if (textValue !=text)
    {
       [textValue retain];
       [text release];
       text = textValue;
    }
}

-(void)dealloc
{
    [text release];
    [super dealloc];
}

@end


接下来,我们需要:
一、添加一个方法,读取当前的text属性:

NSString *theTextValue = [obj text];


(假设 "obj" 是一个MyClass实例)

 这个方法很简单 - 仅仅是返回text属性值。 
二、在另一个方法中,改变text属性:


    [obj setText:newStringValue];


(假设 "obj" 是一个MyClass实例, "newStringValue" 是一个 NSString).
在setText:方法中,由于我们无法确定newStringValue到底是不是一个常量——它可能是任何NSString值,包括在堆中分配的NSString。因此,我们要“retain”这个(将要赋值给text的)对象,以确保这个对象能够和MyClass对象的生命周期一样长。同样,对于已经被替换掉的旧有值,我们不应当再持有它,因此我们释放了它。if语句的使用,是为了减少不必要的赋值——当然,你也可以不用它:


-(void) setText:(NSString *)textValue
{
    [textValue retain];
    [text release];
    text = textValue;
}


即使textValue和text值相同,代码也会被执行,因为我们先在引用计数器上+1,然后再减1。注意,这种写法是错误的:
-(void) setText:(NSString *)textValue
{
    [text release];
    [textValue retain];
    text = textValue;
}

 

这是因为,当“输入”值和要“持有”的值指向了同一个NSString的情况下,会导致字符串最终将被deallocated——第1句代码有可能将引用计数减为0,导致对象被仍会堆里。第2句代码试图去retain这个已经释放的对象(由于二者是同一个)。这种情况不一定发生,但却是一个隐患。
最后,我们实现dealloc方法,在其中释放text对象。我们既然retain了某些东西,就需要记得release它,就好比人临死的时候,要记得把借的书还给图书馆。
值得注意的是,进行空赋值这些代码仍然工作得很好。O-C有个奇怪的特点,允许向nil发送消息(比如release和retain消息)而不会出任何错误。类似于++ 中可以释放一个null指针。

现在,更有趣的事情来了。我们将加入第2个成员变量,以及它的getter和setter。很快你就会看到将发生什么。

//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
    int value;
}

-(void) init;
-(void) logText;
-(NSString*) text;
-(void) setText:(NSString *)textValue;
-(int) value;
-(void) setValue:(int*)intValue;
@end

//MyClass.m file
@implementation MyClass

- (void)init
{
    text = @\"sometext\";
    value = 2;
}

- (void)logText
{
   NSLog(@\"%@\", text);
}

-(NSString *) text
{
    return text;
}

-(void) setText:(NSString *)textValue
{
    if (textValue !=text)
    {
       [textValue retain];
       [text release];
       text = textValue;
    }
}

-(int) value
{
    return value;
}

-(void) setValue:(int)intValue
{
    value = intValue;
}

-(void)dealloc
{
    [text release];
    [super dealloc];
}

@end


这次,我们简单地加入了一个整型变量以及setter/getter方法。但这次,我们不需要retain 和release 。因为整型不是在堆中分配的-它直接存储在MyClass中。我们可以这样干:

    NSString *s = [objtext];
    [objsetText:@\"new string\"];
    int i = [obj value];
    [obj setValue:3];

现在,类似的getter/setter方法在O-C中实在是多得让人写不胜写。因此O-C也提供了更简单的方式为我们自动生成这些方法。我们可以将上述代码修改为:
//MyClass.h file
@interface MyClass: NSObject
{
    NSString *text;
    int value;
}

@property(nonatomic, retain) NSString *text;
@property(nonatomic, assign) int value;

-(void) init;
-(void) logText;
@end

//MyClass.m file
@implementation MyClass

@synthesize text;
@synthesize value;

- (void)init
{
    text = @\"sometext\";
    value = 2;
}

- (void)logText
{
    NSLog(@\"%@\",text);
}

-(void)dealloc
{
    [text release];
    [super dealloc];
}

@end


首先,在MyClass.h中我们移除了两个getter方法和两个setter方法。代之以两个"@property"开头的语句。
在 MyClass.m中,我们删除了所有的setter/getter方法,代之以两个"@synthesize"开头的语句。

这和前面的代码是一模一样的。 回想一下,写一个getter也是很简单的:你只需要知道将返回哪个变量以及变量的类型就行了,这样就很容易写出代码了。对于setter,你需要知道的是:正在对哪个变量赋值,以及它的类型,以及是否是简单赋值(例如int类型的属性)或者是否需要进行retain/release(例如NSString属性)。

然而,现在我们只需要4个"@"语句就行了:

 

@property(nonatomic, retain)NSString *text;

翻译过来就是“我有一个NSString类型的成员变量 'text'。我需要一对getter/setter方法(使用retain/release)”。

@property(nonatomic, assign) intvalue;

翻译过来就是“我有一个int型成员变量 'value'。我需要一对使用简单赋值而不是retain/release的getter/setter方法”。
@synthesize text;

翻译过来就是“请为 'text'自动生成getter/setter方法代码”。
@synthesize value;

翻译过来就是“请为 'value'自动生成getter/setter方法代码”。

注意,我们仍然需要在dealloc方法中release对象。O-C显然还无法自动帮我们做这些事情。

原创粉丝点击