我用了不到一週的時間學習了Objective-C,後面的大部分時間我都在瞭解如何使用IOS的SDK和一些高級的話題,到目前已經有兩個多月的時間了。目前能做一些簡單的應用,但是在寫代碼的時候明顯感覺到基礎不夠紮實,畢竟一週的時間只能對一門語言有個概覽。要想精通一門語言是遠遠不夠的。
所以我把自己學習過程中遇到的一些問題整理在博客上,這也是一個學習理解的過程。
今天要說的內容是Objective-C 中的 @property和@synthesize。在這之前先講講訪問器(Accessor),也就是我們所知道的setter和getter方法。《Cocoa Design Patterns》中的將它歸類爲基礎模式中的一種。訪問器是很重要的技術,用來訪問和設置對象的實例變量(不是指對象本身,而是對象中的屬性)。有時候可能需要用不同的方式或者通過計算等方式來獲取或設置實例變量,訪問器給了我們很大的靈活性。在Cocoa中訪問器有很多的優點:
- 實現靈活性。 可以在訪問器中改變並實現不同的實例變量訪問方式而不影響其他代碼。
- 可維護性。通過訪問器對實例變量的更改易於維護。
- 內存管理。訪問器方法提供了簡單的方法去遵守Cocoa的約定把內存管理代碼隔離在少部分代碼中。
- 支持KVC和KVO。 KVC和KVO是很強大的技術。但是它們依賴於正確命名訪問器。
下面這段代碼簡單的實現了一個訪問器(setter和getter):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//setter -( void )setStuName:(NSString
*)stuName {
//_stuName
是實例變量 if
(_stuName != stuName) { [_stuName
release]; _stuName
= [stuName copy]; } } //getter -(NSString
*)stuName { return
_stuName; } |
上面代碼中的setter中還涉及到一定的內存管理,既然這個技術這麼重要,那麼有沒有一種更方便的方法去做呢?答案就是@property和@synthesize。它們是Objective-C 2.0加入的指令,前者用於聲明,後者用於合成訪問器,結合使用就可以自動生成訪問器了。
下面這段代碼使用@property和@synthesize:
1
2
3
4
5
6
7
8
9
|
@interface
Student : NSObject @property
(nonatomic, copy) NSString *stuName; @end @implementation
Student @synthesize
stuName = _stuName; @end |
這段代碼的效果跟上面代碼的效果是一樣的,是不是很方便呢?
使用@property和@synthesize很方便,但又給我們帶來了很多疑問比如在上面的代碼中又出現了nonatomic和copy,是什麼意思?在@property中還有其他幾個關鍵字,它們都是有特殊作用的,我把它們分爲三類分別是:原子性,訪問器控制,內存管理。
原子性
atomic(默認):atomic意爲操作是原子的,意味着只有一個線程訪問實例變量。atomic是線程安全的至少在當前的訪器上我是安全的。它是一個默認的,但是很少使用。它的比較慢,這跟ARM平臺和內部鎖機制有關。
nonatomic: nonatomic跟atomic剛好相反。表示非原子的,可以被多個線程訪問。它的速度比atomic快。但不能保證在多線程環境下的安全性,在單線程和明確只有一個線程訪問的情況下廣泛使用。
訪問器控制
readwrite(默認):readwrite是默認的,表示同時擁有setter和getter。
readonly: readonly 表示只有getter沒有setter。
有時候爲了語意更明確可能需要自定義訪問器的名字:
1
|
@property
(nonatomic, setter = mySetter:,getter = myGetter ) NSString *name; |
1
|
@property
(nonatomic,getter = isHidden ) BOOL
hidden; |
內存管理
retain:使用了retain意味着實例變量要獲取傳入參數的所有權。具體表現在setter中對實例變量先release然後將參數 retain之後傳給它。下面這段代碼展示了retain類似的行爲:
1
2
3
4
5
6
7
8
|
-( void )setStuName:(NSString
*)stuName { if
(_stuName != stuName) { [_stuName
release]; _stuName
= [stuName retain]; } } |
assign(默認):用於值類型,如int、float、double和NSInteger,CGFloat等表示單純的複製。還包括不存在所有權關係的對象,比如常見的delegate。
strong:是在ARC伴隨IOS引入的時候引入的關鍵字是retain的一個可選的替代。表示實例變量對傳入的參數要有所有權關係即強引用。strong跟retain的意思相同併產生相同的代碼,但是語意上更好更能體現對象的關係。
weak: weak跟assign的效果相似,不同的是weak在對象被回收之後自動設置爲nil。而且weak智能用在iOS 5或以後的版本,對於之前的版本,使用unsafe_unretained。
unsafe_unretained:weak的低版本替代。
copy:copy是爲是實例變量保留一個自己的副本。
現在明白了@property是怎麼回事了,但是@synthesize是怎麼回事,看看之前的第一段代碼:
1
|
@synthesize
stuName = _stuName; |
注意一個問題,我們並沒有聲明_stuName這個變量,這是編譯器自動幫我們創建的。 如果這段指令我換個寫法:@synthesize stuName = a; 並且我們沒有在interface裏面聲明這個變量,那麼會自動創建一個變量a。
如果這裏寫成這樣:
1
2
3
|
<em>@synthesize
stuName; //等同於 @synthesize
stuName = stuName;</em> |
在Xcode4.4中,Xcode添加的一些新的編譯特性。其中一個就是默認合成(Default Synthesis)。默認合成就不再需要顯示的使用@synthesize指令了,這很方便但是要注意的是,默認合成遵守的約定,這裏的也就是命名規則是propertyName = _propertyName。
下面一段代碼幫助理解:
1
2
3
4
|
//對於下面的@propety @property
(nonatomic, copy) NSString *stuName; //默認合成的規則是這樣: @synthesize
stuName = _stuName; |