Objective-C中.h檔案、.m檔案中@interface、@synthesize及其它
很多開發iOS好幾年的老鳥,可能都不太分的清.h檔案和.m檔案裡各種結構的用途和區別。最近仔細研究了一下,寫一篇文章記下來。
一般的,寫一個Class的時候,經常是這種格式(以UIViewController
為例):
.h檔案:
@interface ClassName{
NSString* _value1;
}
@property(nonatomic,assign)NSString* value1; -(void)func1;
.m檔案:
@interface ClassName(){
}
@end @synthesize value1; @implementation ClassName -(void)func1{ } @end
大體上就是這個格式。很多人,包括我,在建立和使用Class時,直接就使用這樣的模板。這個模板裡有一些有意思的小東西,值得探討,比如:
1. 為什麼.h檔案和.m檔案裡各有1個@interface
?它們分別有什麼用?
2. .h中,value1為什麼要定義2遍?
3. @synthesize
有什麼用?
還有一些其它的問題,今天先解決上面提到的這幾個。
為什麼.h檔案和.m檔案裡各有1個@interface?它們分別有什麼用?
.h裡面的@interface
,不消說,是典型的標頭檔案,它是供其它Class呼叫的。它的@property
而.m裡面的@interface
,在OC裡叫作Class Extension,是.h檔案中@interface
的補充。但是.m檔案裡的@interface
,對外是不開放的,只在.m檔案裡可見。
因此,我們將對外開放的方法、變數放到.h檔案中,而將不想要對外開放的變數放到.m檔案中(.m檔案的方法可以不宣告,直接用)。
有的同學看到Class Extension,可能會想到OC裡的@protocol
。是的,它們都是對一個Class的擴充套件。不過它們的區別也很明顯:
Class Extension只能用在能得到原始碼的情況下,而@protocol
因此@protocol
一般用作對一些系統Class的擴充套件,常見的比如對NSString、UIView等。
.h中,value1為什麼要定義2遍?
當然,現在@interface{}
裡的定義也可以省略掉了,不過原理還是要搞清楚。
嚴格來說@interface{}
裡定義的變數,叫作instance variable,它是這個Class內部真正的全域性變數。然而這個instance variable是不對外公開的,因此我們還需要一個對外公開的東西來呼叫,就是@property
@property是對外的,它其實是告訴大家,我這個Class裡,有一個變數的set/get方法。比如,@property NSString* string;
就是說,本Class裡有一個getString/setString供你們呼叫。
因此需要2次宣告。當然現在lldb也升級了,只要你聲明瞭@property
,它就可以自動建立對應的全域性變數。
@synthesize有什麼用?
@property
一個變數後,在@implementation
裡再@synthesize
一下,相信是很多人的習慣。但是為什麼要有這個@synthesize方法呢?
@property
是對外聲明瞭Class的get/set方法,然後我們就需要在.m檔案裡手寫get/set方法。這可就麻煩了,1個變數對應2個方法,假如一個Class裡有10個變數,那豈不是要寫20個方法?煩也煩死嘮。
@synthesize幫我們解決了這個問題。@synthesize
在.m檔案裡自動生成了get/set方法。因此,我們只要在@implementation
後面加上一行:@synthesize
就可以自動生成get/set方法了,省掉了很多麻煩。比如@synthesize value1 = _value1;
的意思就是,將instance variable _value1用作getValue1和setValue1方法裡。
get/set方法有時候是比較複雜的,因為它和變數的屬性相關,就是@property(nonatomic, assign/retain(strong/weak))
這就和記憶體有關了。然而@synthesize為我們做了這些事情,就不要再為這些事情煩惱了!
更方便的是,從Xcode4.4開始,編譯器會自動為每一條@property
都新增一條對應的@synthesize
,因此以後我們只要寫一個@property就可以了!