Objective-C入門 簡介Cocoa框架

Cocoa Framework簡稱Cocoa,它是Mac OS X上的快速應用程序開發(RAD, Rapid Application Development)框架,一個高度面向對象的(Object Oriented)開發框架。不管您是資深的Mac開發人員,仍是即將踏入Mac開發世界的新新人類,Cocoa都是您開發應用程序的瑞士軍刀、樂高積木,它是您構建Mac OS X應用程序最強大、最高效的工具。值得一提的是,蘋果公司之因此可以開發出衆多頂級軟件,其實也正是由於有着Cocoa這個祕密武器。Cocoa是Mac OS X上原生支持的應用程序開發框架,蘋果公司強烈推薦全部Mac開發人員使用。 程序員

 

骨灰話題:Hello World!編程

 

相信對於任何一個開發人員,Hello World!都應該是個熟悉無比的東西。那麼,Cocoa的Hello World!程序您看得懂麼?設計模式

 

import api

 

int main (int argc, const char argv[]) 數組

 

NSAutoreleasePool pool [[NSAutoreleasePool alloc] init]; 數據結構

 

NSLog(@"Hello, World!"); 框架

 

[pool drain]; 編程語言

 

return 0; 函數

 

工具

Hmm... 看不明白?再也不仔細看看?仍是看不明白?

 

不論您是否看得明白,首先,和絕大多數您所見過的C程序同樣,任何一個Cocoa應用程序都有一個主函數:

 

int main(int argc, const char argv[])

 

主函數是應用程序的主入口,也是一切開始和結束的地方。是的,沒錯!從表面上看,這些代碼和常見的C程序的代碼沒有什麼區別,並且事實上,它們和C程序的代碼的的確確沒有什麼區別。

 

接下來你該問我,那什麼是Foundation?Foundation.h裏裝的又是什麼?什麼是NSAutoreleasePool?那些中括號又是什麼?...... 別急,在後續的幾章裏咱們會慢慢把這麼多陌生的面孔熟悉起來,固然我也能夠如今就大體的解釋一下:

 

Foundation全稱Foundation Framework,是Cocoa的一個子開發框架。Foundation裏包含了Cocoa中最基本的一些類,它們在一個Mac應用程序中一般負責對象管理、內存管理、容器等相關數據結構的操做。Foundation.h是Foundation的頭文件,一旦引入了這個頭文件,咱們就能夠在本身的程序裏使用任何在Foundation裏聲明的類。例如在上述代碼中,NSAutoreleasePool就是Foundation中聲明的一個類,它爲應用程序提供可控制的延遲對象釋放的內存管理。至於那些方括號,它們是Objective-C裏最最基本的語法成分,一對方括號中間的內容表示對對象(或類)進行一次方法的調用。

 

若是您沒有聽明白,請不要惶恐不安,我們在下面的幾章裏慢慢說。另外,Cocoa的國際音標是['koukou]但願你們能把這個單詞的音讀對。

 

我其實很C

 

在使用Cocoa進行應用程序開發的時候,Objective-C是咱們首選的語言。(固然,Cocoa也經過官方、第三方等途徑,構建了Cocoa-Ruby、Cocoa-Python等編程語言上的橋接,使不管是來自Ruby仍是Python世界的開發人員可以使用他們熟悉的語言快速上手。)不過在這裏,咱們仍是要首推Objective-C做爲一個Cocoa程序的開發語言,緣由有二:

 

其1、Objective-C其實是C的超集。

 

Objective-C的運行環境庫(Runtime Library)徹底是由C編寫的,所以任何一個Objective-C消息派發(Message Dispatching),都會被替換成Objective-C運行環境中的某個或某幾個C函數的調用。這種機制爲Objective-C帶來了高效的消息派發和對C代碼徹底原生的兼容。

 

其2、整個Cocoa Framework都是由Objective-C/C實現的。

 

所以在開發一個Cocoa應用程序的時候,Objective-C是咱們不二的選擇。

 

當咱們說到「Objective-C」的時候,儘管編程模型和C不一樣,儘管語法看似有些奇怪,但事實咱們所討論的依然仍是C語言。由於Objective-C確實是C,說的簡單些:

 

Objective-C就是擁有一個面向對象層(Object Oriented Layer)的C。而Objective-C正是經過從Smalltalk進化而來的這種語法,實現了對這個面向對象層的支持。所以若是您正在使用Objective-C開發一個Cocoa應用程序,同時又但願在某些代碼的某些位置插入一些C代碼,那就請放心大膽的繼續吧!

 

設計模式深刻骨髓:無處不在的MVC

 

在傳統的開發模式中,咱們很容易陷入「膠水代碼」的陷阱裏。所謂的「膠水代碼」,顧名思義,就是僅僅用來保持用戶界面數據、狀態同步的函數調用的集合體。這些函數調用扯不斷,理還亂,而且使代碼變的很是冗長、易出錯、不易維護。

 

爲了解決這個問題,Cocoa提供了多個內部機制:Key-Value Coding(KVC)、Key-Value Observing(KVO)、Key-Value Binding(KVB)。這些機制經過規定了一組通用的Cocoa命名法則、調用規則等,實現了以下功能:

 

1. 使用一對高度規範化的訪問方法,獲取以及設置任何對象的任何屬性的值(所謂的屬性既能夠是個實實在在的成員變量,也能夠是經過一對成員方法所抽象出的該對象的一個性質)。

 

2. 經過繼承一個特定的方法,而且指定但願監視的對象及但願監視的屬性名稱,就能在該對象的指定屬性的值發生改變時,獲得一個「通知」(儘管這不是一個真正意義上的通知),而且獲得相關屬性的值的變化(原先的值和改變後的新值)。

 

3. 經過一個簡單的函數調用,使一個視圖對象的一個指定屬性隨時隨地都和一個控制器對象或模型對象的一個指定屬性保持同步。

 

一個開發者能夠利用這些功能,將本身建立的類寫的很範化、很通用,而後經過KVB將多個視圖「綁定」到一個或多個控制器上,再將控制器綁定到最底層的數據模型上。這樣一來,任何一個視圖上的改變都會經過KVC被「壓」到控制器裏,而後又經過KVC從控制器「壓」到數據模型裏。當數據模型中的值發生改變時,一個或多個控制器又會獲得KVO的「通知」,接着只要被綁定了的視圖又會獲得這一個或多個控制器的KVO「通知」。這樣以來,開發者只須要在適當的時候告訴Cocoa,什麼對象的什麼值該和什麼對象的什麼值綁定,就能夠了,其他數據更新、格式化等工做Cocoa都會替你完成。

 

是否是很方便呢?

 

Easy Life之一:內存管理

 

內存管理是令不少開發人員頭大的問題,在Cocoa中,內存管理是經過引用計數器模型完成的。

 

Cocoa中的每一個對象都擁有一個引用計數器,用來維持本身的生命週期。每當一個對象須要「使用」或「佔有」另外一個對象的時候,它經過向該對象發送一個retain消息來對該對象的引用計數器進行自增,而當它再也不須要(或使用完)該對象的時候,它經過向該對象發送一個release消息來對該對象的引用計數器進行自減。當一個對象的引用計數器自減到零時,該對象就會被釋放。

 

下面咱們來看一個例子,例如:

 

NSString *aString [[NSString alloc] initWithString:@"This is demo."]; 

這段代碼會建立一個NSString對象,並對其進行初始化。當一個對象被建立的時候,它的引用計數器會被設爲1。所以當您再也不須要該對象,只要直接對其發送release消息,它就會被直接析構。當您有別的代碼塊也須要使用這個NSString時,您能夠對這個NSString對象調用一次retain來增長它的引用計數器:

 

[aString retain]; 這個時候,它的引用計數器值就是2了。當您使用完該對象時,若是您對該對象調用過retain,那就應該「對稱」地調用一次release。這時一種基本地編程規範,我將它稱爲「誰retain,誰release」。

 

[aString release]; 

調用完之後,引用計數器再次回到1。最後,當咱們完全不須要這個對象的時候,咱們能夠這麼作:

 

[aString release]; 

 

aString nil; 

上兩行代碼中,第一句會負責將這個NSString對象析構,第二句會負責將原來指向這個NSString對象的指針(NSString *aString)「歸零」,由於「野指針」隨時可能形成您程序的異常及崩潰。

 

聽着是否是挺簡單?

 

固然也有稍微複雜一些的狀況,話說一開始咱們有提到一個叫做NSAutoreleasePool的類吧?NSAutoreleasePool是Cocoa內存管理機制裏很重要的一個環節。咱們在本着「誰retain,誰release」的對象使用的大前提下,常常會碰到這麼一個問題,那就是咱們但願返回一個在局部中建立的對象:

 

(NSString)demoString 

 

 

NSString *result [[NSString alloc] initWithString:@"This is demo."]; 

 

return result; 

 

在「誰retain,誰release」的原則下,上面的代碼顯然只負責了retain(alloc調用等效於retain),可是沒有負責release,所以這麼寫可能會形成內存泄露,由於調用這個方法(或這個API)的代碼段並不知道到底是否須要負責釋放這個方法(或這個API)的返回值。

 

可是若是咱們將它直接release了:

 

(NSString)demoString 

 

 

NSString *result [[NSString alloc] initWithString:@"This is demo."]; 

 

[result release]; 

 

return result; 

 

那return的將會是個「野指針」(或者若是你乾的足夠乾淨,return的是個零指針),不是咱們須要的值。所以咱們須要一個可以延遲釋放,而且可以自動釋放的機制。因而,人們發明了名叫NSAutoreleasePool的又一個輪子,而代碼則變成了這個樣子:

 

(NSString)demoString 

 

 

NSString *result [[NSString alloc] initWithString:@"This is demo."]; 

 

[result autorelease]; 

 

return result; 

 

在對一個對象發送了autorelease以後,這個對象不會被當即釋放,而是被「登記」到了離它最近的一個NSAutoreleasePool對象上。當該NSAutoreleasePool被清空或釋放的時候,這個「登記」了的對象纔會被真正發送一個release消息。

 

Easy Life之二:容器

 

容器是讓多數程序員又愛又恨的東西。在Cocoa中,容器是如此的簡單易用以致於您一旦用過,就會對它們「愛不釋手」。Cocoa中的容器類主要有這麼幾個:NSString、NSArray、NSDictionary、NSSet和NSIndexSet等,它們都是Foundation Framework的一部分。

 

爲何人們會對Cocoa的容器「愛不釋手」呢?

 

緣由一:NSArray、NSDictionary、NSSet都不強制其內部元素類型的一致性。舉個簡單的例子:

 

NSString *aString [NSString stringWithString:@"This is demo."];

 

NSNumber *aNumber [NSNumber numberWithInteger:0];

 

NSArray *anArray [[NSArray alloc] initWithObjects:aString, aNumber, nil];

 

在上述例子中,咱們首先創建了一個NSString對象,而後又創建了一個NSNumber對象,最後咱們將這兩個NSString和NSNumber對象都「塞」到了一個NSArray對象中。

 

有夠爽吧?連想都別想,什麼東西都能往裏面裝(基本類型、結構體除外)!

 

緣由二:容器類的「可修改」和「不可修改」

 

上面咱們展現的NSString、NSArray、NSDictionary、NSSet以及NSIndexSet等,都是容器的「不可修改」的版本。所謂的「不可修改」,指的是這個容器一旦被建立之後,咱們就不能夠經過代碼修改它的集合。那若是咱們須要修改(例如添加、刪除、替換)這些容器的元素,該怎麼辦呢?

 

Cocoa中幾乎全部的容器類,都提供了另一個「可修改」的版本。例如:繼承自NSString的NSMutableString、繼承自NSArray的NSMutableArray、繼承自NSDictionary的NSMutableDictioanry、繼承自NSSet的NSMutableSet以及繼承自NSIndexSet的NSMutableIndexSet等。這些「可修改」的版本提供了簡單直觀的方法,用來修改其內部的元素。例如:

 

NSString *aString [NSString stringWithString:@"This is demo."]; 

 

NSNumber *aNumber [NSNumber numberWithInteger:0]; 

 

NSMutableArray *aMutableArray [NSMutableArray array]; 

 

[aMutableArray addObject:aString]; 

 

[aMutableArray addObject:aNumber]; 

 

[aMutableArray removeObjectAtIndex:0]; 

 

[aMutableArray removeAllObjects]; 

在上述代碼中,第1、二行創建了一個NSString對象和一個NSNumber對象。第三行創建了一個NSMutableArray對象(也就是一個「可修改」的NSArray對象)。第4、五行經過-addObject:方法分別將第1、二行創建的NSString對象和NSNumber對象加入了這個「可修改」的NSArray裏。第六行則是根據咱們給定的索引號0,刪除了數組中的第一個元素。第七行的-removeAllObjects最後一口氣將數組中存在的全部元素通通刪除(置空數組)。

相關文章
相關標籤/搜索