1 Interface(介面約定)
Interface理解為介面概念,於JAVA\C#中的介面有所不同的是Obj-C中的介面應該理解為一種非正式協議,Obj-C中的Interface只是表明應該會處理其中聲明的訊息(方法),但是不是必須處理。
表明Sample Interface中,約定了應該會處理HelloWorld訊息,但是Sample.m中我們可以不去實現對HelloWorld的處理,這樣編譯器會給出警告但是編譯可以通過,但是在程式中向Sample發送該訊息會引發異常。
2 Protocol(正式協議)
Protocol(正式協議)看上去更正規一些,語義上更強烈一些:要求採用該協議的類,"必須"實現協議中約定的方法。但是比較娛樂的是,即使是號稱正式協議,編譯器在編譯時間,遇到不守規矩的情況,仍然只是給出警告。你會覺得Protocol跟Interface比起來,都是類似的概念,Protocol設計純屬多餘。其實不然,Protocol存在的一個重要意義在於:
Protocol(正式協議)可以將業務中的方法定義剝離出來,形成一個單獨的檔案,這跟傳統OO中的提取介面是不謀而合的。如果遇到二個系統需要交換資料,可以制定一套雙方都遵守的Protocol,然後這二個系統中都把這個協議檔案添加到項目中,實現它即可。
這一功能,非正式協議(@interface)是做不到的。因為在Obj-C中是不允許多繼承的,雙方系統可能都需要繼承某一個類以實現某些功能,這時候只能實現一個協議(Protocol)。 此外,Obj-C 2.0中對協議還做了一些擴充,允許把協議中的方法標識為“必須實現(@required)”和“可選實現(@optional)”二類,如果協議中的方法被標識為@optional,即使採用該協議的類不實現這些方法,編譯器也不會給出警告。這樣介面約定的很多作用就可以由協議來實現,不過協議中不能含有資料(但是介面約定中可以有資料成員)。
NSObject是一個Interface也是一個Protocol,而Interface NSObject實現了Protocol NSObject,在Obj-c的OO世界中,身為萬物之祖的NSObject其實也就一個"正式協議”,所以從NSObject派生出的所有類,都只是在遵守一個或多個協議而已。
3 Categories (類型分類,非正式協議)
非正式協議並沒有設計為正式協議的寬鬆版本,而是設計為Class Categories(類型分類)。Categories是Objective-C裡面最常用到的功能之一。大體上說,Categories可以讓我們給已經存在的類增加方法,而不需要增加一個子類。而且不需要知道它內部具體的實現。如果我們想增加某個framework內建的類的方法,這非常有效。如果我們想在我們程式工程的NSString能夠增加一個方法,我們就可以使用Categories,不需要自己實現一個NSString的子類。比如,我們想在NSString裡面增加一個方法來判斷它是否是一個URL,那我們就可以這麼做:
1) 在categoriesTest.h標頭檔中:
1: @interface NSString (URLDetecter)
2: - (BOOL) isURL;
3: @end
這跟類的定義非常類似。區別就是category沒有父類,而且在括弧裡面要有category的名字。名字可以隨便取,但是習慣叫法會讓人比較明白category裡面有些什麼功能的方法。這裡是具體的實現。但是要注意,這本身並不是一個判斷URL很好的實現。我們主要是為了整體的瞭解category的概念。
2) 在categoriesTest.m中給出實現
1: #import "categoriesTest.h"
2: @implementation NSString (URLDetecter)
3: - (BOOL) isURL{
4: if ( [self hasPrefix:@"http://"] )
5: return YES;
6: else
7: return NO;
8: }@end
3) 在main.m中使用NSString的時候如下:
1: NSString* string1 = @"http://www.CocoaDev.cn/";
2: NSString* string2 = @"Pixar";
3: if ([string1 isURL]) NSLog(@"string1 is a URL");
4: if([string2 isURL]) NSLog(@"string2 is a URL");
4) 如果在main.m沒有import標頭檔categoriesTest.h,會有如下警告
warning: 'NSString' may not respond to '-isURL'
warning: (Messages without a matching method signature
warning: will be assumed to return 'id' and accept
warning: '...' as arguments.
編譯器認為NSString不會對訊息isURL作出回應。
此時運行得到的結果如下:
5) 如果在main.m中import標頭檔categoriesTest.h
運行結果如下:
跟子類不一樣,category不能增加成員變數。我們還可以用category來重寫類原先的存在的方法,但是這需要非常非常小心。記住,當我們通過category來修改一個類的時候,它對應用程式裡的這個類所有對象都起作用。