標籤:
分類
在Objective-C中,除了通過建立子類的方式來向類添加新方法外,還可以通過分類的方式。分類提供了一種簡單的方式,將類的定義模組化到相關方法的組或分類中,它還提供了擴充現有類定義的簡便方式,並且不需要訪問類的原始碼,也無須建立子類。
比如:
//SomeClass+MathOps.h#import "SomeClass.h"@interface SomeClass (MathOPs)-(SomeClass *) add: (SomeClass *)s;-(SomeClass *) sub: (SomeClass *)s;-(SomeClass *) div: (SomeClass *)s;-(SomeClass *) mul: (SomeClass *)s;@end
這裡不用列出父類,也不用向編譯器告知執行個體變數,因為從import的檔案的介面部分已經這樣做了。
可以將所有的方法的定義放在一個實現部分。也就是說,可以在一個實現檔案中定義SomeClass.h介面部分中的所有方法,以及MathOps分類中的所有方法。或者,在單獨的實現部分定義分類的方法,這種情況下,這些方法的實現部分必須找出方法所屬的分類。如@implementation SomeClass (MathOps) 這樣。
如果將分類放到一個主類定義檔案中,那麼這個類的所有使用者都將訪問這個分類中的方法。如果不能直接修改原始的標頭檔,則只能將分類單獨儲存檔案。
類的擴充
建立一個未命名的分類,且在()內不指定名字,這是一種特殊情況,這種特殊文法定義為類的擴充。定義一個像這樣的未命名分類時,可以通過定義附加的執行個體變數來擴充類,這在命名的分類中是不允許的。未命名分類中聲明的方法需要在主實現地區實現,而不是在分離的實現地區中實現。如果沒有實現未命名分類的介面部分列出的全部方法,編譯器會發出警告。
比如,在一個類的實現檔案中:
//SomeClass.m#import "SomeClass.h"//類的擴充@interface SomeClass ()@property int pp;-(void)someFunc;@end//--------------------------@implementation SomeClass@synthesize pp;.....@end
通過添加一個新的執行個體變數和方法擴充了這個類,併合成了存取方法。
未命名分類是非常有用的,因為它們的方法都是私人的。如果需要寫一個類,其資料和方法僅供類本身使用,未命名分類比較合適。
分類的注意事項:
分類可以覆寫該類中的另一個方法,不過這是拙劣的設計,因為覆寫一個方法之後,再也不能訪問原來的方法。如果需要覆寫,正確的選擇是建立子類,子類中覆蓋父類的方法,此時仍然可以通過super來調用父類原方法。
可以擁有許多分類,如果一個方法定義在多個分類中,該語句不會指定使用哪個分類。
通過分類添加新方法來擴充類不僅會影響這個類,同時也會影響它的所有子類。
協議
協議是多個類共用的一個方法列表,協議中列出的方法並沒有相應的實現,計劃由其他人來實現的。協議提供一種方式,用指定的名稱定義一組多少有點相關的方法。這些方法有的是必須實現的(@required),有的是可選的(@optional)。
定義協議是使用@protocol指令,後面加上協議名稱。
當採用某協議時,在@interface行最後的一對<>中列出協議名稱即可,同時在實現部分至少實現協議的必須實現方法。
比如:@interface SomeClass:SuperClass <SomeProtocol>
協議是無類的,它不引用任何類,任何類都可以遵守某個協議。可以使用comformsToProtocol:方法檢查一個對象是否遵循某協議。
代理
協議也是一種兩個類之間的介面定義。定義了協議的類可以看做是將協議定義的方法代理給了實現它們的類,這樣,類的定義可以更為通用,因為具體的動作由代理類來承擔,來響應某些事件或者定義某些參數。Cocoa和iOS非常依賴代理這個概念。比如UITableView類,這個類不清楚表格的標題是什麼,需要包含多少區塊或是包含多少行,填充表格的內容是什麼。所以,代理定義了一個UITableViewDataSource協議,如果它需要資訊,比如表格中每個區塊有多少行,它就會調用類中實現協議的相關方法。UITableView類還定義了其他的協議如UITableViewDelegate,協議還定義了一些方法,如表格某行被選中需要怎樣,UITableView不知道要做什麼,所以將這個代理給了實際使用者。
非正式協議
非正式協議實際上是一個分類,列出了一組方法但是沒有實現他們。每個人都繼承相同的根對象,因此,非正式協議通常是為根類定義的。有時,非正式協議又被稱為抽象協議。因為非正式協議本身不是協議而是分類,所以編譯器不提供協議相關的協助,不會存在遵守或者不遵守非正式協議或者由編譯器測試這樣的概念。
合成對象
除了通過派生子類和分類可以擴充類定義以外,還有一項技術可以定義一個類包含其他類的一個或多個對象,這個新類的對象就是合成對象,因為它是由其他對象組成的。
通過派生子類擴充父類,子類就整合了父類所有的執行個體變數和方法,一些情況下,有些方法並不適用於子類,然而子類的使用者卻有可能會訪問它們。作為建立子類的替代方式,可以定義一個新類,它包含要擴充類的執行個體變數,然後,只需在新類中定義適合該類的方法。比如:
@interface NewClass:NSObject{ SomeClass *s; }-(void)newFunc;@end
這裡需要注意,與子類擴充不同,子類版本允許直接存取父類的方法,這裡NewClass的對象不能直接存取SomeClass的方法了,而是在自己的方法裡比如newFUnc裡邊,通過執行個體變數s來訪問那些可以被用到的方法。記住,這裡在初始化時,需要覆寫init或者自訂初始化方法來給s分配空間。
iOS開發筆記系列-基礎5(分類和協議)