Cocoa
骨灰話題:Hello
相信對於任何一個開發人員,Hello
import
int
NSAutoreleasePool
NSLog(@"Hello,
[pool
return
}
Hmm...
不論您是否看得明白,首先,和絕大多數您所見過的C程序同樣,任何一個Cocoa應用程序都有一個主函數:
int
主函數是應用程序的主入口,也是一切開始和結束的地方。是的,沒錯!從表面上看,這些代碼和常見的C程序的代碼沒有什麼區別,並且事實上,它們和C程序的代碼的的確確沒有什麼區別。
接下來你該問我,那什麼是Foundation?Foundation.h裏裝的又是什麼?什麼是NSAutoreleasePool?那些中括號又是什麼?......
Foundation全稱Foundation
若是您沒有聽明白,請不要惶恐不安,我們在下面的幾章裏慢慢說。另外,Cocoa的國際音標是['koukou]但願你們能把這個單詞的音讀對。
我其實很C
在使用Cocoa進行應用程序開發的時候,Objective-C是咱們首選的語言。(固然,Cocoa也經過官方、第三方等途徑,構建了Cocoa-Ruby、Cocoa-Python等編程語言上的橋接,使不管是來自Ruby仍是Python世界的開發人員可以使用他們熟悉的語言快速上手。)不過在這裏,咱們仍是要首推Objective-C做爲一個Cocoa程序的開發語言,緣由有二:
其1、Objective-C其實是C的超集。
Objective-C的運行環境庫(Runtime
其2、整個Cocoa
所以在開發一個Cocoa應用程序的時候,Objective-C是咱們不二的選擇。
當咱們說到「Objective-C」的時候,儘管編程模型和C不一樣,儘管語法看似有些奇怪,但事實咱們所討論的依然仍是C語言。由於Objective-C確實是C,說的簡單些:
Objective-C就是擁有一個面向對象層(Object
設計模式深刻骨髓:無處不在的MVC
在傳統的開發模式中,咱們很容易陷入「膠水代碼」的陷阱裏。所謂的「膠水代碼」,顧名思義,就是僅僅用來保持用戶界面數據、狀態同步的函數調用的集合體。這些函數調用扯不斷,理還亂,而且使代碼變的很是冗長、易出錯、不易維護。
爲了解決這個問題,Cocoa提供了多個內部機制:Key-Value
1.
2.
3.
一個開發者能夠利用這些功能,將本身建立的類寫的很範化、很通用,而後經過KVB將多個視圖「綁定」到一個或多個控制器上,再將控制器綁定到最底層的數據模型上。這樣一來,任何一個視圖上的改變都會經過KVC被「壓」到控制器裏,而後又經過KVC從控制器「壓」到數據模型裏。當數據模型中的值發生改變時,一個或多個控制器又會獲得KVO的「通知」,接着只要被綁定了的視圖又會獲得這一個或多個控制器的KVO「通知」。這樣以來,開發者只須要在適當的時候告訴Cocoa,什麼對象的什麼值該和什麼對象的什麼值綁定,就能夠了,其他數據更新、格式化等工做Cocoa都會替你完成。
是否是很方便呢?
Easy
內存管理是令不少開發人員頭大的問題,在Cocoa中,內存管理是經過引用計數器模型完成的。
Cocoa中的每一個對象都擁有一個引用計數器,用來維持本身的生命週期。每當一個對象須要「使用」或「佔有」另外一個對象的時候,它經過向該對象發送一個retain消息來對該對象的引用計數器進行自增,而當它再也不須要(或使用完)該對象的時候,它經過向該對象發送一個release消息來對該對象的引用計數器進行自減。當一個對象的引用計數器自減到零時,該對象就會被釋放。
下面咱們來看一個例子,例如:
NSString
這段代碼會建立一個NSString對象,並對其進行初始化。當一個對象被建立的時候,它的引用計數器會被設爲1。所以當您再也不須要該對象,只要直接對其發送release消息,它就會被直接析構。當您有別的代碼塊也須要使用這個NSString時,您能夠對這個NSString對象調用一次retain來增長它的引用計數器:
[aString
[aString
調用完之後,引用計數器再次回到1。最後,當咱們完全不須要這個對象的時候,咱們能夠這麼作:
[aString
aString
上兩行代碼中,第一句會負責將這個NSString對象析構,第二句會負責將原來指向這個NSString對象的指針(NSString
聽着是否是挺簡單?
固然也有稍微複雜一些的狀況,話說一開始咱們有提到一個叫做NSAutoreleasePool的類吧?NSAutoreleasePool是Cocoa內存管理機制裏很重要的一個環節。咱們在本着「誰retain,誰release」的對象使用的大前提下,常常會碰到這麼一個問題,那就是咱們但願返回一個在局部中建立的對象:
(NSString)demoString
{
NSString
return
}
在「誰retain,誰release」的原則下,上面的代碼顯然只負責了retain(alloc調用等效於retain),可是沒有負責release,所以這麼寫可能會形成內存泄露,由於調用這個方法(或這個API)的代碼段並不知道到底是否須要負責釋放這個方法(或這個API)的返回值。
可是若是咱們將它直接release了:
(NSString)demoString
{
NSString
[result
return
}
那return的將會是個「野指針」(或者若是你乾的足夠乾淨,return的是個零指針),不是咱們須要的值。所以咱們須要一個可以延遲釋放,而且可以自動釋放的機制。因而,人們發明了名叫NSAutoreleasePool的又一個輪子,而代碼則變成了這個樣子:
(NSString)demoString
{
NSString
[result
return
}
在對一個對象發送了autorelease以後,這個對象不會被當即釋放,而是被「登記」到了離它最近的一個NSAutoreleasePool對象上。當該NSAutoreleasePool被清空或釋放的時候,這個「登記」了的對象纔會被真正發送一個release消息。
Easy
容器是讓多數程序員又愛又恨的東西。在Cocoa中,容器是如此的簡單易用以致於您一旦用過,就會對它們「愛不釋手」。Cocoa中的容器類主要有這麼幾個:NSString、NSArray、NSDictionary、NSSet和NSIndexSet等,它們都是Foundation
爲何人們會對Cocoa的容器「愛不釋手」呢?
緣由一:NSArray、NSDictionary、NSSet都不強制其內部元素類型的一致性。舉個簡單的例子:
NSString
NSNumber
NSArray
在上述例子中,咱們首先創建了一個NSString對象,而後又創建了一個NSNumber對象,最後咱們將這兩個NSString和NSNumber對象都「塞」到了一個NSArray對象中。
有夠爽吧?連想都別想,什麼東西都能往裏面裝(基本類型、結構體除外)!
緣由二:容器類的「可修改」和「不可修改」
上面咱們展現的NSString、NSArray、NSDictionary、NSSet以及NSIndexSet等,都是容器的「不可修改」的版本。所謂的「不可修改」,指的是這個容器一旦被建立之後,咱們就不能夠經過代碼修改它的集合。那若是咱們須要修改(例如添加、刪除、替換)這些容器的元素,該怎麼辦呢?
Cocoa中幾乎全部的容器類,都提供了另一個「可修改」的版本。例如:繼承自NSString的NSMutableString、繼承自NSArray的NSMutableArray、繼承自NSDictionary的NSMutableDictioanry、繼承自NSSet的NSMutableSet以及繼承自NSIndexSet的NSMutableIndexSet等。這些「可修改」的版本提供了簡單直觀的方法,用來修改其內部的元素。例如:
NSString
NSNumber
NSMutableArray
[aMutableArray
[aMutableArray
[aMutableArray
[aMutableArray
在上述代碼中,第1、二行創建了一個NSString對象和一個NSNumber對象。第三行創建了一個NSMutableArray對象(也就是一個「可修改」的NSArray對象)。第4、五行經過-addObject:方法分別將第1、二行創建的NSString對象和NSNumber對象加入了這個「可修改」的NSArray裏。第六行則是根據咱們給定的索引號0,刪除了數組中的第一個元素。第七行的-removeAllObjects最後一口氣將數組中存在的全部元素通通刪除(置空數組)。