property & synthesize

今天來聊聊一下自己對於@synthesize和 @property的見解。

也就是新手常稿混的 @synthesize foo = _foo , self.foo 跟 _foo的差別。

食蜂

一般我們設全域變數通常會再@interface 中 例如

1
2
3
4
@interface Test : NSObject
{
NSString *carName;
}

在@interface 中可以設定@private @protected @public 不過這不是重點今天先不聊

當你在@interface中定義變數時, 在m檔中賦值都是直接賦值的. 我們稱為iVar (instance variable)

ex carName = @"BMW" myName = carName (myName = BMW)

當你寫成@property (nonatomic,retain)NSString *carName;

不僅僅是對外公開了這個屬性, 還為它之後賦值作變化

在m檔中~我們在以前會看到這兩種寫法
@synthesize carName = _carName; or @synthesize carName;

這裡 carName 等於property 的屬性名 _carName是個iVar

在Xcode 4.5版後~如果你不設定@synthesize 他會自動幫我們補上 Var = _Var ,

在m檔中~你會發現 有兩種方法可以賦值和取值 self.carName 和 _carName .

這邊的 _carName 就相當等於iVar 的功能,是這個m檔中的全域變數。 是直接賦值的。

但是很多人會稿混,self.var 和 _var 的不同

當我們使用self.carName時,我們會調用Setter

所以在objc 2.0版本前 需手動補上setter 和getter

上面的@interface 就會多了兩個method
- (void) setcarName(NSString *)carName

- (NSString *) carName

一般簡單的Setter 我們會這樣寫

1
2
3
4
5
- (void) setcarName(NSString *)carName
{
_carName = [carName retain]; //retain是取決於你property 中設定的值
}

getter 會變成這樣

1
2
3
4
5
- (NSString *) carName
{
return _carName;
}

到此有注意到什麼嗎??

經由self 給值的他會通過setter 等於我們調用 [self setcarName:@””];

他會經由Property 中你設定的值 會先retain(or copy ,assign) 一次再賦值給全域變數

你取值時,也是得到retain過後的值, 為什麼要先retain呢

這就牽扯到物件的所有權 其實setter的完整寫法應該如下

1
2
3
4
5
6
7
8
9
- (void) setcarName(NSString *)carName
{
if (_carName != carName){ //先判斷是否跟上次存的值相同,不同時才去進行賦值
[_carName release]; //先釋放舊的物件
_carName = [carName retain]; // 把新的物件retain 把控制權給 _carName
//因為carName 跳出method後就被釋放
}
}

getter 則是完全不變,所以我們建議賦值時都給用self. (dot noation) 去賦值。

除非你這個值是不會變動或是不在被autorelease 的物件用到,不然需手動加retain

這也就是很多書上寫的, 你alloc retain copy一個Object 需手動釋放,

誰用他誰就負責釋放.

在dealloc 下面,我個人是建議釋放掉iVar 也就是

1
2
3
- (void) dealloc{
[_carName release];
}

至於寫成 @synthesize carName;

則是把原本的_carName 用carName取代掉,其他功能都一樣。

不過就是因為寫成這樣~很多人會混用self.carName = 和carName = ;

這是相當不好的習慣,而且對於記憶體的使用很難掌握。

當然你都是用ARC的去寫專案,不用清楚這個也可以,因為Xcode都幫你做好了,

只是有些地方你混用程式Crash後,你不清楚記憶體管理流程,Debug會很辛苦。