IOS——開發語言(二)

更多關於內存管理:

Objective-C的內存管理系統基於引用記數。所有我們需要關心的就是跟蹤我們引用,以及在運行期內是否真的釋放了內存。

用最簡單的術語來解釋,當我們alloc一個對象的時候,應該在某個時候retain了它。每次我們調用了alloc或者retain之後,我們都必須要調用release。

這就是引用記數理論。但是在實踐的時候,只有兩種情況我們需要創建一個對象:

1. 成爲一個類的成員變量

2. 只臨時的在一個函數裏面被使用

在更多的時候,一個成員變量的setter應該僅僅autorelease舊的對象,然後retain新的對象。我們只需要在dealloc的時候調用release就可以了。

所以真正需要做的就是管理函數內部的local的引用。唯一的原則就是:假如我們alloc或者copy了一個對象,那麼我們在函數結束的時候需要release或者autorelease它。假如我們是通過別的方式創建的,就不管。

這裏是管理成員對象的例子:

  1. - (void) setTotalAmount: (NSNumber*)input
  2. {
  3. [totalAmount autorelease];
  4. totalAmount = [input retain];
  5. }
  6. - (void) dealloc
  7. {
  8. [totalAmount release];
  9. [super dealloc];
  10. }

這裏是本地引用的例子。我們只需要release我們用alloc創建的對象:

  1. NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];
  2. NSNumber* value2 = [NSNumber numberWithFloat:14.78];
  3. // only release value1, not value2
  4. [value1 release];

這裏是用本地引用對象去設一個成員變量的例子:

  1. NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75];
  2. [self setTotal:value1];
  3. NSNumber* value2 = [NSNumber numberWithFloat:14.78];
  4. [self setTotal:value2];
  5. [value1 release];

注意到如何管理本地引用其實都是一樣的。不管你是否把它設給了一個成員變量。我們無須考慮setters的內部實現。

如果我們很好的理解了這些的話,我們基本上理解了80%的Objective-C內存管理方面的內容了。

屬性Properties:

前面我們寫caption和author的accessors的時候,你可以已經注意到了代碼非常簡明,應該可以被抽象提取出來。

屬性在Objective-C裏是一個新的功能。他可以讓我們自動的生成accessors,另外還有一些別的優點。我們可以把上面Photo的類轉成用屬性來實現:

上面那個類原先的實現是這樣:

  1. #import
  2. @interface Photo : NSObject {
  3. NSString* caption;
  4. NSString* photographer;
  5. }
  6. - (NSString*) caption;
  7. - (NSString*) photographer;
  8. - (void) setCaption: (NSString*)input;
  9. - (void) setPhotographer: (NSString*)input;
  10. @end

假如用屬性來實現就是這樣:

  1. #import
  2. @interface Photo : NSObject {
  3. NSString* caption;
  4. NSString* photographer;
  5. }
  6. @property (retain) NSString* caption;
  7. @property (retain) NSString* photographer;
  8. @end

@property是Objective-C來聲明屬性的編譯指令。括號裏面的"retain"指明瞭setter需要retain輸入的對象。這行其他的部分指定了屬性的類型以及名字。

下面讓我們來看看這個類的實現:

  1. #import "Photo.h"
  2. @implementation Photo
  3. @synthesize caption;
  4. @synthesize photographer;
  5. - (void) dealloc
  6. {
  7. [caption release];
  8. [photographer release];
  9. [super dealloc];
  10. }
  11. @end

@synthesize指令自動的生成了我們的setters和getters。所以我們只需要實現類的dealloc方法。

Accessors只有當他們原先沒有的時候,纔會被生成。所以可以放心大膽的去用@synthesize來指定屬性。而且可以隨意實現你自己的getter和setter。編譯器會自己去找哪個方法沒有。

屬性聲明還有別的選項,但是限於篇幅層次,我們下次再介紹。

Logging:

在Objective-C裏,往console寫日記非常簡單。事實上NSLog()跟C語言的printf()兩個函數幾乎完全相同,除了NSLog是用額外的“%@”去獲得對象。

  1. NSLog ( @"The current date and time is: %@", [NSDate date] );

我們可以log一個對象到console裏去。NSLog函數調用要輸出對象的description方法,然後打印返回的NSString。我們可以在自己的類裏重寫description方法,這樣我們就可以得到一個自定義的字符串。

調用nil對象的方法(Calling Methods on Nil):

在Objective-C裏,nil對象被設計來跟NULL空指針關聯的。他們的區別就是nil是一個對象,而NULL只是一個值。而且我們對於nil調用方法,不會產生crash或者拋出異常。

這個技術被framework通過多種不同的方式使用。最主要的就是我們現在在調用方法之前根本無須去檢查這個對象是否是nil。假如我們調了nil對象的一個有返回值的方法,那麼我們會得到一個nil返回值。

我們可以通過nil對象讓我們的dealloc函數實現看上去更好一些:

  1. - (void) dealloc
  2. {
  3. self.caption = nil;
  4. self.photographer = nil;
  5. [super dealloc];
  6. }

之所以可以這麼做是因爲我們給把nil對象設給了一個成員變量,setter就會retain nil對象(當然了這個時候nil對象啥事情也不會做)然後release舊的對象。這個方式來釋放對象其實更好,因爲這樣做的話,成員變量連指向隨機數據的機會都沒有,而通過別的方式,出現指向隨機數據的情形機會不可避免。

注意到我們調用的self.VAR這樣的語法,這表示我們正在用setter,而且不會引起任何內存問題。假如我們直接去設值的話,就會有內存溢出:

  1. // incorrect. causes a memory leak.
  2. // use self.caption to go through setter
  3. caption = nil;


Categories:

Categories是Objective-C裏面最常用到的功能之一。 基本上category可以讓我們給已經存在的類增加方法,而不需要增加一個子類。而且不需要知道它內部具體的實現。

如果我們想增加某個framework自帶的類的方法,這非常有效。如果我們想在我們程序工程的NSString能夠增加一個方法,我們就可以使用category。甚至都不需要自己實現一個NSString的子類。

比如,我們想在NSString裏面增加一個方法來判斷它是否是一個URL,那我們就可以這麼做:

  1. #import
  2. @interface NSString (Utilities)
  3. - (BOOL) isURL;
  4. @end

這跟類的定義非常類似。區別就是category沒有父類,而且在括號裏面要有category的名字。名字可以隨便取,但是習慣叫法會讓人比較明白category裏面有些什麼功能的方法。

這裏是具體的實現。但是要注意,這本身並不是一個判斷URL很好的實現。我們主要是爲了整體的瞭解category的概念。

  1. #import "NSString-Utilities.h"
  2. @implementation NSString (Utilities)
  3. - (BOOL) isURL
  4. {
  5. if ( [self hasPrefix:@"http://"] )
  6. return YES;
  7. else
  8. return NO;
  9. }
  10. @end

現在我們可以在任何的NSString類對象裏都可以調用這個方法了。下面的代碼在console裏面打印的"string1 is a URL":

  1. NSString* string1 = @"http://www.CocoaDev.cn/";
  2. NSString* string2 = @"Pixar";
  3. if ( [string1 isURL] )
  4. NSLog (@"string1 is a URL");
  5. if ( [string2 isURL] )
  6. NSLog (@"string2 is a URL");

跟子類不一樣,category不能增加成員變量。我們還可以用category來重寫類原先的存在的方法,但是這需要非常非常小心。

記住,當我們通過category來修改一個類的時候,它對應用程序裏的這個類所有對象都起作用。

後記

上面Objective-C的比較基礎的大概的講了一下。Objective-C還是比較好上手的。沒有特別的語法需要去學習。而且一些概念在Objective-C裏面被反覆運用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章