Objective-C
最初起源于 NeXTSTEP
操作系統(tǒng)莱衩,之后喬布斯回到蘋果掺逼,便將它在OS X和iOS中繼承了下來坑赡。
20世紀(jì)80年代初奄妨,Brad Box
和Tom Love
以SmallTalk-80
語言為基礎(chǔ)發(fā)明了Objective-C
涂籽,Smalltalk
是歷史上第二個(gè)面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,也就是說:Objective-C就是C語言面向?qū)ο骃mallTalk語法話的結(jié)果展蒂。
讓我們來看看早起SmallTalk的語法特點(diǎn):
在 Smalltalk 中一切皆對象又活,一切調(diào)用都是發(fā)消息
比如下面的表達(dá)式:
2 + 3
它的意義是:向?qū)ο?code>2發(fā)送消息+
,參數(shù)為對象3
锰悼。
再比如用一個(gè)工廠方法來實(shí)例化一個(gè)對象:
p := Person name: 'Sai DiCaprio' age: 12
為Person類添加一個(gè)方法
greet: name
| message |
message := 'Hello ', name.
Transcript show: message.
在方法定義里柳骄,管道|
包著的本地變量,然后是方法的實(shí)現(xiàn)箕般,把‘Hello’
放到了變量message
里耐薯,然后用逗號符把它和變量name
連接起來。
p := Person new.
p greet: 'Jack'.
這時(shí)Transcript會(huì)輸出 Hello Jack
丝里。
從上可以看出曲初,消息傳遞機(jī)制成了C語言進(jìn)化為OC的最大障礙,要實(shí)現(xiàn)向一個(gè)target ( class / instance )
發(fā)送消息名selector
動(dòng)態(tài)尋找到函數(shù)實(shí)現(xiàn)地址IMP
并調(diào)用杯聚,為了解決這一難題臼婆,需要提供一系列在Build Time
無法實(shí)現(xiàn)的運(yùn)行時(shí)函數(shù)支持,這些函數(shù)慢慢封裝完整幌绍,便出現(xiàn)了一套API:Runtime
颁褂。
早期的Objective-C = C + Preprocessor + Runtime
既然已經(jīng)形成了一套健全的面向?qū)ο蟮腃語言體系,那么我們來看看早期的Objective-C
代碼是如何書寫的
@interface Person{
NSString *_name;
int _age;
}
- (NSString *)name;
- (void)setName:(NSString *)name;
- (int)age;
- (void)setAge:(int)age;
@end
上面的代碼聲明了一個(gè)類Person
傀广,他有2個(gè)成員變量颁独,并分別為其提供了set
和get
方法。
秉著誰創(chuàng)建伪冰,誰釋放誓酒;誰引用,誰管理
的MRC原則贮聂,在實(shí)現(xiàn)文件中便有了下面的代碼
@implementation Person
- (NSString *)name{
return _name;
}
- (void)setName:(NSString *)name{
if (_name != name){
[_name release];
_name = [name copy];
}
return _name;
}
- (int)age{
return _age;
}
- (void)setAge:(int)age{
_age = age;
}
@end
可以看到靠柑,僅僅創(chuàng)建了2個(gè)變量就為類帶來了這么大的代碼量,在成員變量多的情況下寂汇,通篇垃圾代碼病往,于是Objective-C 2.0
馬上就出現(xiàn)了新的語法@property
關(guān)鍵字
它用來讓編譯器自動(dòng)幫我們生成成員變量和其對應(yīng)的get和set方法的聲明。
比如Person類的聲明中便化為這樣:
@interface Person
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
注意:這時(shí)的@property并不像現(xiàn)在一樣會(huì)幫我們自動(dòng)生成成員變量的setter和getter方法的實(shí)現(xiàn)
在實(shí)現(xiàn)方面有另外一個(gè)關(guān)鍵字:@synthesize
幫我們根據(jù)屬性修飾符自動(dòng)合成setter
和getter
的實(shí)現(xiàn)骄瓣。
@implementation Person
@synthesize name = _name;
@synthesize age = _age;
@end
后來自動(dòng)合成的@synthesize
可以不用寫了停巷,默認(rèn)就是上面的代碼。這樣一來榕栏,整個(gè)類變得輕快了很多畔勤。
但是也會(huì)有這樣的需求:比如不希望系統(tǒng)幫我們自動(dòng)實(shí)現(xiàn)setter
和getter
,而由我們自己來實(shí)現(xiàn)扒磁,便出現(xiàn)了@dynamic
關(guān)鍵字庆揪,雖然編譯器會(huì)通過,但是如果在運(yùn)行過程中方法調(diào)用了對應(yīng)的setter
和getter
方法妨托,但是發(fā)現(xiàn)沒有手動(dòng)實(shí)現(xiàn)那么就會(huì)崩潰報(bào)unrecognized selector sent to instance 0x.......
的錯(cuò)誤缸榛。編譯時(shí)沒問題吝羞,運(yùn)行時(shí)才執(zhí)行相應(yīng)的方法,這就是所謂的動(dòng)態(tài)綁定内颗。
總結(jié):
- @synthesize 告訴編譯器幫我們合成屬性的getter和setter的實(shí)現(xiàn)
- @dynamic 告訴編譯器不要幫我自動(dòng)合成屬性钧排,而由我們自己實(shí)現(xiàn)getter和setter的實(shí)現(xiàn)
既然現(xiàn)在的@property會(huì)幫我們自動(dòng)合成autosynthesize那么@dynamic和synthesize如今還有什么意義呢?
回答這個(gè)問題前均澳,我們要搞清楚一個(gè)問題恨溜,什么情況下不會(huì)autosynthesis(自動(dòng)合成)?
- 同時(shí)重寫了 setter 和 getter 時(shí)
- 重寫了只讀屬性的 getter 時(shí)
- 使用了 @dynamic 時(shí)
- 在 @protocol 中定義的所有屬性
- 在 category 中定義的所有屬性
- 重載的屬性
當(dāng)同時(shí)重寫了setter和getter或者重寫了只讀屬性的getter時(shí)找前,系統(tǒng)就不會(huì)幫我們自動(dòng)合成糟袁,就意味著ivar也不會(huì)被生成,所以躺盛,這種情況下有兩種方案:
- 自己添加ivar
- 使用@synthesize
也就是說项戴,當(dāng)你想手動(dòng)管理 @property
的所有內(nèi)容時(shí),你就會(huì)嘗試通過實(shí)@property
的所有存取方法
或者使用@dynamic
來達(dá)到這個(gè)目的槽惫,這時(shí)編譯器就會(huì)認(rèn)為你打算手動(dòng)管理 @property
肯尺,于是編譯器就禁用了自動(dòng)合成。