Object-C 聲明屬性爲什麼用下劃線,代碼規範和編程風格

Object-C 聲明屬性爲什麼用下劃線,代碼規範和編程風格

 
在閱讀和書寫關於iPhone編程的代碼的時候,發現有很多這樣的情況:
看到很多源代碼裏面,使用前面帶下劃線變量,然後在@synthesize 語句中在用一個不帶下劃線的變量名。

這樣做,到底有什麼作用?

因爲我常常是以這種方式來做的:
*.h中申明變量

 

#import <UIKit/UIKit.h>

@interface NewPlayerController : UIViewController{


    NSString *test;


}

@property(nonatomic,retain) NSString *test;


@end


在*.m中


 


#import "NewPlayerController.h"

@implementation NewPlayerController

@synthesize test;


- (void)viewDidLoad

{

    [super viewDidLoad];

 

    test=[[NSString alloc] initWithFormat:@"test"];


}


@end


但是,發現很多別人寫的代碼是這樣子的:


*.h中申明變量

 

#import <UIKit/UIKit.h>

@interface NewPlayerController : UIViewController{

NSString* _test;

    

}

@property(nonatomic,retainNSString *test;


@end


在*.m中


 


#import "NewPlayerController.h"

@implementation NewPlayerController

 

@synthesize test=_test;


- (void)viewDidLoad

{

    [super viewDidLoad];

 

    _test=[[NSString allocinitWithFormat:@"test"];

 

   // 或者這樣

    self.test=[[NSString alloc] initWithFormat:@"test"];

 

     

}


@end


這兩種方式到底有什麼區別?用那種好?


帶着這個疑問,我去網上搜索"代碼風格",“編碼規範”,“下劃線公約”。解釋太寬泛了,根本沒有一個定論。

於是只有理論+實踐自己在走一回吧。


開始把:


第一種方式,就是平常我們說的不帶下劃線的那種方式:


 

self.test=[[NSString alloc] initWithFormat:@"test"];

    NSLog(@"self.test的應用計數:%d",[self.test retainCount]);

    NSLog(@"test的應用計數:%d",[test retainCount]);

但是,我驚奇的發現,輸出竟然這樣:

 

2012-11-17 15:52:29.604 ArtTV[901:14303] self.test的應用計數:2

2012-11-17 15:52:33.264 ArtTV[901:14303] test的應用計數:2


self.test和test的地址是相同的,說明是同一個對象的應用,但爲什麼,應用計數會是2呢?


於是,代碼變成這樣寫(僅僅是,self.test換成test):

 

test=[[NSString alloc] initWithFormat:@"test"];

    NSLog(@"self.test的應用計數:%d",[self.test retainCount]);

    NSLog(@"test的應用計數:%d",[test retainCount]);


輸出:

 

2012-11-17 15:59:58.274 ArtTV[954:14303] self.test的應用計數:1

2012-11-17 15:59:59.718 ArtTV[954:14303] test的應用計數:1



這纔是我們所期望的。應用計數應該爲1纔對,爲什麼會變成2呢?


恍然大悟了!原來原因出在這裏:我們申明test時,用的屬性修飾符retain。

當我們,使用self.test時,就使用了編譯器爲我們生成的setXXX方法。在該方法中retainCount被加1,所以,變爲2.


這樣的花,如果,我們在代碼中,直接用

self.test=[[NSString allocinitWithFormat:@"test"];

這行代碼後,test變量的應用計數變成了2:

相當於:

首先,聲明一個字符串對象,這時候,引用計數爲1.

其次,再將test的值賦給self.test。(相當於,使用了setXXX方法,讓retainCount,加1),導致應用計數變成2.

所以,在類中,如果,僅僅是指針賦值,(將一個對象的指針賦給另一個指針)儘量避免使用self.test進行賦值。這樣會引起引用計數+1,容易引起釋放內存泄漏。而直接用test來賦值。


也就是,在方法中,使用self.xxxx,進行賦值,就會使用編譯器生成的setXXX方法,從而根據申明對象時的屬性(copy,retain,assign)進行調用setXXX方法。

如果,只用屬性之間來賦值(test= newValue;,就是不帶self),那麼,僅僅是指針之間的賦值。


第二種方式,就是帶下劃線的那種方式:


這樣,讓我們驗證:

代碼中,我們這麼寫:

test=[[NSString allocinitWithFormat:@"test"];

我們會收到一個錯誤提示:

Object-C <wbr>聲明屬性爲什麼用下劃線,代碼規範和編程風格
看來,不能直接訪問,test,而要用_test來代替。


不管它,那就用它推薦的方法,繼續寫完:


 

self.test=[[NSString alloc] initWithFormat:@"test"];

    NSLog(@"self.test的應用計數:%d",[self.test retainCount]);

    NSLog(@"_test的應用計數:%d",[_test retainCount]);

運行代碼,輸出如下:


 

2012-11-17 16:30:39.525 ArtTV[1042:14303] self.test的應用計數:2

2012-11-17 16:30:41.553 ArtTV[1042:14303] _test的應用計數:2


運行輸出,很顯然,應用計數爲2,不是我們想要的結果。原因,跟我們討論的第一種情況,是一樣的。


這僅僅是一種調用的另一種方式:

默認情況,調用test,當我們申明test=_test;時候,那麼在類內部使用_test。

在使用_test,時候,也僅僅是指針的賦值。

使用self.test,就是要調用編譯器生成的響應的getXXX,setXXX方法了。


爲了證明我們的想法,我們將代碼修改成這樣:


 

_test=[[NSString alloc] initWithFormat:@"test"];

    NSLog(@"self.test的應用計數:%d",[self.test retainCount]);

    

    NSLog(@"_test的應用計數:%d",[_test retainCount]);


輸出如下:

 

2012-11-17 16:36:09.089 ArtTV[1074:14303] self.test的應用計數:1

2012-11-17 16:36:10.701 ArtTV[1074:14303] _test的應用計數:1



關於,使用方式,我們就將到這裏吧。親自動手,實驗一下。就明白其中的奧妙了!


但是,還沒有結束!


另一個疑惑,也隨之而來。

我們用那種方式好呢????


我看了一些帖子,說,蘋果不提倡在我們定義的類中使用“_xxxx”,這種形式的屬性聲明,因爲,在很多蘋果提供的框架中,大量使用“_xxxx”這種屬性聲明。

——————————————————————————————————————

 

Cocoa編碼指南: 編程公約:

避免使用下劃線作爲前綴,特別是在私有方法中。蘋果公司保留並使用本公約。使用第三方可能會導致命名空間衝突;自己不知不覺中,可能會覆蓋現有的私有方法,帶來災難性的後果。

——————————————————————————————————————

打開一個看看:

Object-C <wbr>聲明屬性爲什麼用下劃線,代碼規範和編程風格
確實,如此啊!


在這種情況下,如果,我們,繼承了某個框架類,並且無意間聲明的“_xxxx”屬性跟父類的相同,那麼可能就會覆蓋掉,從而引發不可估計的後果!


但是,我看蘋果幫助文檔中寫的許多例子也在用“_xxxx”這種方式啊!所以,我覺的可以用,但要注意!Object-C <wbr>聲明屬性爲什麼用下劃線,代碼規範和編程風格


爲什麼是可以用呢?

因爲個人感覺:“_xxxx”確實很好用!

1.從風格上表明類的內部變量。

2.意在指明這個變量是內部變量(類外部不會使用。。。)

3.外部訪問用obj.xxxxx, 避免對類變量的直接訪問。

4.這樣的話,要是需要直接引用變量就用_xxxx,當需要用get,set方法時,就用self.xxx。


匯成一句話:

下劃線和非下劃線的使用,可以說是一種習慣問題吧。不用太過於糾結!

默認情況下,@synthesize name;編譯器爲我們生成的get,set方法中所使用的變量名稱,跟我們申明的變量名稱時一樣的(僅僅用self.namename來區分確實不夠理想)。


但是,當我們用@synthesize name=_name;時,就爲屬性取了一個別名,那樣的話,指針變量,跟編譯器生成的get,set方法爲屬性賦值時就容易區分了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章