[ios] @synthesize obj=_obj的意义详解 @property和@synthesize【转】

http://hi.baidu.com/feng20068123/item/ca8952fa661e5342932af2c2

写的非常不错,攒一个!!!!

我们在进行iOS开发时,经常会在类的声明部分看见类似于@synthesize window=_window; 的语句,那么,这个window是什么,_ window又是什么,两个东西分别怎么用,这是一个比较基本的问题,也关乎我们理解Objective-C中对类、类的属性、类的存取器、类的局部变量的统一理解。
在32位系统中,如果类的 @interface 部分没有进行 ivar 声明,但有 @property 声明,在类的 @implementation 部分有响应的 @synthesize,则会得到类似下面的编译错误:
Synthesized property 'xX' must either be named the same as a compatible ivar or must explicitly name an ivar
在 64-bit时,运行时系统会自动给类添加 ivar,添加的 ivar 以一个下划线"_"做前缀。
上面声明部分的 @synthesize window=_window; 意思是说,window 属性为 _window 实例变量合成访问器方法。
也就是说,window属性生成存取方法是setWindow,这个setWindow方法就是_window变量的存取方法,它操作的就是_window这个变量。通过这个看似是赋值的这样一个操作,我们可以在@synthesize 中定义与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问。

下面是一个常见的例子
写法一:
 

@interface MyClass:NSObject{    

        MyObjecct *_myObject;  

}  

@property(nonamtic, retain) MyObjecct *myObject;  

@end  

  

@implementatin MyClass  

@synthesize myObject=_myObject;  

 
 
写法二:
 

@interface MyClass:NSObject{  

        

}  

@property(nonamtic, retain) MyObjecct *myObject;  

@end  

  

@implementatin MyClass  

@synthesize myObject=_myObject;  

 
这 个类中声明了一个变量_myObject,又声明了一个属性叫myObject,然后用@synthesize生成了属性myObject的存取方法,这 个存取方法的名字应该是:setmyObject和getmyObject。@synthesize myObject=_myObject的含义就是属 性myObject的存取方法是做用于_myObject这个变量的。这种用法在Apple的Sample Code中很常见。
弄明白了这个语句的意思之后,我们也就清楚了myObject和_myObject的区别,那么,在使用的时候,有什么需要注意的地方,大家应该也都清楚了。是的,myObject是属性,而_ myObject才是变量,我们最终操作的变量都是myObject。
那么,同样是存取操作,语句
 

self.nameVarPtr = [[ObjectName alloc] init]   

 
 

nameVarPtr = [[ObjectName alloc] init]  

两种赋值方式的区别何在呢?

 

self.nameVarPtr=xxx 这种赋值方式等价于调用 [self setnameVarPtr:xxx], 而setnameVarPtr:xxx的方法的实现又是依赖于@property的属性的,比如retain,assign等属性。

 

nameVarPtr = xxx 的 赋值方式,仅仅是对一个指针进行赋值。nameVarPtr仅仅是一个指针变量,记录了xxx的地址。在这个过程中不会调用setter方法,不会调用 setter方法,就和@property没有关系,从而,也和retain,assign等属性没有关系。这种赋值方式就是一个简单的指针赋值。

 

综上,对成员变量进行赋值,为防内存泄露需要注意的点:

1.self调用setter方法的方式

ObjectName*  tmp= [[ObjectName alloc] init];

self.nameVarPtr =tmp;                 //retainCount=2

[tmp release];                               //retainCount=1

 

2.指针赋值方式,不会调用setter方法

nameVarPtr= [[ObjectName alloc] init]; // retainCount=1

 

所以,笔者建议大家在对某个变量进行赋值操作的时候,尽量要写self.myObj = xxx; 这才是最可靠的方法。

 

坏的做法

@interface Foo : NSObject {

        @private

NSObject* myObj_;

}

 

@property(strong, nonatomic) NSObject* myObj;

 

@end

 

// …

 

@implementation Foo

 

@synthesize myObj = myObj_;

 

  • @end

好的做法

@interface Foo : NSObject

 

@property(strong, nonatomic) NSObject* myObj;

 

@end

 

// …

 

@implementation Foo

 

@synthesize myObj = myObj_;

 

@end

You may still need to declare the underlying name of the variable if you need to access it directly, as when writing custom getters and setters:

当你自己在为实例变量写setter和getter的时候,如果你在其中需要直接访问变量的话,你得声明名字带下划线的变量:

错误的写法

@interface Foo : NSObject

 

@property(strong, nonatomic) NSObject* myObj;

 

@end

 

// …

 

@implementation Foo

 

@synthesize myObj;

 

- (NSObject*)myObj

{

        return self.myObj; // 会递归调用getter!

}

 

- (void)setMyObj:(NSObject*)myObj

{

        self.myObj = myObj; // 会递归调用setter!

}

 

@end

正确的写法

@interface Foo : NSObject

 

@property(strong, nonatomic) NSObject* myObj;

 

@end

 

// …

 

@implementation Foo

 

@synthesize myObj = myObj_;

 

- (NSObject*)myObj

{

        return myObj_; // 没问题.

}

 

- (void)setMyObj:(NSObject*)myObj

{

        // 没问题

        myObj_ = myObj; // 进行赋值(ARC会处理必要的retain和release)

}

 

@end

 

解释的非常好  ,学习了

 

posted @ 2013-03-27 14:23  金建彤  阅读(252)  评论(0编辑  收藏  举报