天天看點

學習Objective-C--第四天

教程詳細:

      技術:Objective-C    難度:初學者     完成時間:20-35分鐘

  歡迎來到學習Objective-C系列教程的第四部分,到目前為止,我們在理論,原則以及語言功能。今天,我們會建立一個像前面舉的汽車例子那樣的簡單類。我們的類會較長的描述汽車,并允許我們讀寫其屬性。在今天的例子之後,你将能夠用Xcode建立自己的類并熟練運用它。

   到目前為止,我們已經收到了一些很好的回報,包括通過郵件,留言,twitter等。我很高興看到這麼多童鞋對這系列教程感興趣,更高興的是,看到大家都動起手來實踐并提出問題。呵呵,繼續努力吧!

準備開始

    首先用Xcode建立一個新項目,在Mac OS X 的分隔符下,點選Application,然後點選Command Line Tool,最後,更改下清單框設定Foundation的類型。

學習Objective-C--第四天

  儲存該項目,我就命名為CarApp吧,當這項目視窗出現時,我們需要建立一個新類。點選Command-N(或 File>New File),在Mac OS X下導航到Cocoa并選擇Objective-C類。確定子類是繼承于NSObject并點選下一步。命名你的類為SimpleCar并確定 .h 檔案被建立了,然後就儲存。

  我們的類現在已經建立好了,但它是空的。讓我們為它填充些代碼吧。還記得在Objective-C中,我們把代碼分成兩部分嗎:接口與實作。它讓在接口的工作變得有邏輯意義,是以這是我們的初衷。

編寫接口

    打開SimpleCar.h檔案,目前的狀态看起來是這樣的:

2.        
3. @interface SimpleCar : NSObject {         
4.        
5. }         
6.        
7. @end       

  首先,我們引入Cocoa.h,這使我們可以獲得像NSString,NSMutableString等這樣的東東。然後,我們建立類(SimpleCar)作為NSObject的子類。

  現在, 我們需要确定我們的類需要儲存什麼樣的資訊了。既然我們像平常一樣用汽車,我們需要存儲有關汽車的相關資訊,例如:

  • make      牌子   
  • model    型号
  • VIN        汽車識别碼

  還有更多資訊我們可以寫進,但現在不會這樣。對于其中的每個屬性,我們需要用一個合适的資料類型去存儲。牌子和型号是字元範疇(像檔案,号碼和标點符号),是以用string是比較合适的喲。VIN(汽車識别碼)僅僅是由數字組成。我們的代碼看起來會像這樣(省略前面):

1. @interface SimpleCar : NSObject {         
2.     NSString* make;         
3.     NSString* model;         
4.     NSNumber* vin;         
5. }         
6.        
7. @end       

    我們之前也提過了,為了讀寫類的資料,會用到一個方法。是以,要設定變量,我們需要增加方法。要做這樣,我們提出四點:一個設定牌子,一個設定型号,一個設定VIN,以及最後一個方法用來設定牌子和型号(隻是為了告訴大家怎樣使用多個參數罷了)。

1. @interface SimpleCar : NSObject {         
2.    NSString* make;         
3.    NSString* model;         
4.    NSNumber* vin;         
5. }         
6.        
7. // set methods         
8. - (void) setVin:   (NSNumber*)newVin;         
9. - (void) setMake:  (NSString*)newMake;         
10. - (void) setModel: (NSString*)setModel;         
11.        
12. // convenience method         
13. - (void) setMake: (NSString*)newMake         
14.        andModel: (NSString*)newModel;         
15.        
16. @end        

  我們在大括号@end之間聲明方法,在方法之前放置 “-“是要告訴編譯器這個方法是執行個體方法。一個執行個體方法是依靠執行個體執行的方法。相反,一個”+”表示這個方法是類方法,這方法的執行并不需要一個單獨的對象,這接下來會講到。

  我們的第一個方法(setVin)傳回void,并以一個NSNumber作為參數。我們的第二個方法(setMake)也相類似,也傳回void,并以一個NSString作為參數。第三個方法除了方法名都相似。

  我們最後一個方法也是傳回void,但需要兩個NSString類型的參數:newMake和newModel。這些方法的命名是與大多數Objective-C方法相似的,都是以簡單英語命名。是以,當你讀到這方法時,能夠明顯知道其含義。記住方法的名記是重要的,在這種情況下為:”setMake,andModel“--所有參數名都包括在方法名裡了。

  有一點值得注意的是,我們使用(void)是因為我們不需要傳回任何東西。既然所有要做的隻是設定值,并不需要傳回任何東西(例如一表示成功的資訊):

  下一步,我們會添加用來通路值的方法。雖然我們稱這些方法為get 方法和set方法,我們隻用”set”和”get”。怎樣命名你的方法由你決定,但是用到了”get”會常于的,有助于避免混淆。

  我們的set方法看起來會像這樣:

1. // set methods         
2. - (void) setVin:   (NSNumber*)newVin;         
3. - (void) setMake:  (NSString*)newMake;         
4. - (void) setModel: (NSString*)newModel;         
5.        
6. // convenience method         
7. - (void) setMake: (NSString*)newMake         
8.        andModel: (NSString*)newModel;         
9.        
10. // get methods         
11. - (NSString*) make;         
12. - (NSString*) model;         
13. - (NSNumber*) vin;       

  要注意的是, get方法名和類裡的變量名相同。這樣當我們讀書變量時更簡單。當你直接通路這變量,基本上對get方法是透明的。

編寫實作

  現在,我們的接口已經存在了,并且知道類要幹什麼了,是以要實作我們的方法了。往回看,我們有四個方法需要實作的:setVin, setMake ,setModel 和setMake:andModel。在移動檔案之前,複制這些方法的聲明到粘貼闆(Cmd+C)。現在關閉SimpleCar.h 并在編輯器裡打開 SampleCar.m ,在@implementation和@end之間粘貼下這些方法聲明。如下:

[email protected] SimpleCar         
2.      
3.// set methods         
4.- (void) setVin:   (NSNumber*)newVin;         
5.- (void) setMake:  (NSString*)newMake;         
6.- (void) setModel: (NSString*)newModel;         
7.       
8.// convenience method         
9.- (void) setMake: (NSString*)newMake         
10.        andModel: (NSString*)newModel;         
11.       
12.// get methods         
13.- (NSString*) make;         
14.- (NSString*) model;         
15.- (NSNumber*) vin;         
16.        

  顯然,這是不對的,我們需要做的是,把花括号的地方和方法的内部工作交換,像這樣:

1:  @implementation SimpleCar         
3:  // set methods         
4:  - (void) setVin: (NSNumber*)newVin {         
6:  }         
8:  - (void) setMake: (NSString*)newMake {         
10:  }         
12:  - (void) setModel: (NSString*)newModel {         
14:  }         
16:  - (void) setMake: (NSString*)newMake         
17:          andModel: (NSString*)newModel {         
19:  }         
21:  // get methods         
22:  - (NSString*) make {         
24:  }         
26:  - (NSString*) model {         
28:  }         
30:  - (NSNumber*) vin {         
32:  }         
34:  @end        

  現在,我們需要為方法添加一些代碼了。讓我們以getter方法作為開始吧,對于每一個getter方法,我們需要做的就是確定方法傳回打算傳回的資料。由于這個原因,我們的getter方法像這樣:

1:  - (NSString*) make {         
2:      return make;         
3:  }         
5:  - (NSString*) model {         
6:      return model;         
7:  }         
9:  - (NSNumber*) vin {         
10:      return vin;         
11:  }        

  記住:方法傳回的變量是決定于接口檔案的,不要把方法名和變量名混淆了喲!

  這很簡單吧,我們調用make方法,這make方法傳回一個NSString指針--這情況下是make變量。同樣對于model和vin(除了vin傳回一個數字)。

  現在說說setter方法,首先,我們看看這些代碼,然後将越過去,我們的setter方法看上去像這樣的:

1:  // set methods         
2:  - (void) setVin: (NSNumber*)newVin {         
4:      [vin release];         
5:      vin = [[NSNumber alloc] init];         
6:      vin = newVin;         
8:  }         
10:  - (void) setMake: (NSString*)newMake {         
12:      [make release];         
13:      make = [[NSString alloc] initWithString:newMake];         
15:  }         
17:  - (void) setModel: (NSString*)newModel {         
19:      [model release];         
20:      model = [[NSString alloc] initWithString:newModel];         
22:  }         
24:  // convenience method         
25:  - (void) setMake: (NSString*)newMake         
26:          andModel: (NSString*)newModel {         
28:      // Reuse our methods from earlier         
29:      [self setMake:newMake];         
30:      [self setModel:newModel];         
32:  }       

  set方法比get方法有那麼一點點棘手。我們想把值傳遞到每個方法裡,為了它們屬于這個類。首先,公開這些變量,他們被配置設定了記憶體,如果不被配置設定,則為零,而忽略了對象傳遞給他們的消息。當我們讨論記憶體管理的時候,我們将介紹這些問題。

  因為我們在setter方法為我們的對象配置設定記憶體,當這對象被從記憶體裡釋放時,我們要確定釋放它們。做到這一點,我們需要自定義一個釋放方法,像這樣的:

1:  -(void) dealloc         
2:  {         
3:      [vin release];         
4:      [make release];         
5:      [model release];         
6:      [super dealloc];         
7:  }       

測試類

     恭喜你,如果你按照上面所說的做,你現在應該有一個可工作的類了。是以,讓我們測試它吧。

   打開項目主檔案(我的是叫CarApp.m),預設情況下看起來像這樣的:

3:  int main (int argc, const char * argv[]) {         
5:      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];         
7:      // Insert custom code here...         
8:      NSLog(@"Hello, World!");         
10:      [pool drain];         
11:      return 0;         
12:  }       

   删除評論和NSLog行,因為我們不再需要它們了。

   為了開始使用我們的類,我們需要把它放時程式裡。在下面原始的#import行加上下面這行:

1:  #import "SimpleCar.h"       

   我們的類現在是可用的了,為了測試它,但我們需要建立一個執行個體。這裡有完整的代碼:

2:  #import "SimpleCar.h"         
4:  int main (int argc, const char * argv[]) {         
6:    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];         
8:      SimpleCar *myCar = [[SimpleCar alloc] init];         
10:      NSNumber *newVin = [NSNumber numberWithInt:123];         
12:      [myCar setVin:newVin];         
13:      [myCar setMake:@"Honda" andModel:@"Civic"];         
15:      NSLog(@"The car is: %@ %@", [myCar make], [myCar model]);         
16:      NSLog(@"The vin is: %@", [myCar vin]);         
18:      [myCar release];         
20:    [pool drain];         
22:    return 0;         
23:  }       

   首先,我們建立一個SimpleCar命叫myCar的執行個體的指針。接着,我們使用記憶體分布和初始化--這些會在下面說到的:

   其次,既然我們需要傳遞一個NSNumber給setVin方法,在這就建立一個呗。再次,我們建立一個命叫newVin的NSNumber執行個體的指針,并且初始化值為123。 “123”是一個整型,這就是我們使用數字的原因了。

   接下來,我們調用我們的方法,首先我推送myCar該接收的消息,并使用setVin方法。冒号後的值(之前建立的NSNumber)是我們提供給這方法的。接着,我們調用兩個參數的setMake方法。這些參數由一個@打頭,是為了告訴編譯器緊接的是一個string。

   最後,我們釋放myCar,因為之前用了它。接下來的會更多的讨論記憶體管理。

   我們的類在工作了,為了證明這動作,我們加一些NSLog語句來列印一些值到控制台吧。如果你打開控制台(Run>Console),建立并運作你的程式,你會看到像這樣的:

學習Objective-C--第四天

屬性和合成(Synthesize)

    看看上面的代碼,很多看起來像是乏味的。例如,在我們的getter方法裡,隻做了傳回一個執行個體變量,但這就要用了三行代碼去做如此簡單的事。同樣,在我們的setter方法裡,我們僅設定了執行個體變量。除了我們方法有兩個參數,看起來是重複和臃腫呀。然而,Objective-C為了解決這問題,用了@property和@synthesize,放在我們的通路方法那裡,并給出了許多簡潔的編碼。

   這樣,我們新接口檔案看起來像使用屬性那樣了:

1:  #import "SimpleCar.h"         
3:  @implementation SimpleCar         
5:  @synthesize make, model, vin;         
7:  - (void) setMake: (NSString*)newMake         
8:          andModel: (NSString*)newModel {         
10:      [self setMake:newMake];         
11:      [self setModel:newModel];         
13:  }         
15:  @end       

  這看起來是不是更優雅呢?這樣想吧,@property替換了所有getter和setter方法的接口聲明,而@synthesize則替換它們實際的方法。這樣 , getter和setter可以被動态建立了,我們不需要浪費時間去建立它們,除非我們需要一些特别的事情。

  小結:

    到現在,你應該很好的掌握了類,對象和執行個體了。當然,如果你還沒有建立類,那就另當别論了,這東西是需要時間的。通過例子學習是更好的方法,如果你不想動手,那至少也要下載下傳代碼去閱讀一下,以確定百分百知道這是神馬回事。

繼續閱讀