iOS開發:Category(分類)和Extension(類擴展)的解惑篇。

Category (分類) 和 Extension (類擴展)的理解和區別:

Category

  • Category解釋、定義
  • Category的用途
  • Category的注意

Extension

  • Extension解釋、定義
  • Extension的作用

*******************************華麗麗的分割線*******************************

Cagegory(分類)解釋、定義

Category:用于向已經存在的類添加方法從而達到擴展已有類的目的,在很多情況下Category也是比創建子類更優的選擇,而新添加的方法也會被被擴展的類的所有子類自動繼承,但是Category原則上無法添加屬性。
先看一下蘋果對Category的解釋:
Category 是表示一個指向分類的結構體的指針,其定義如下:

typedef struct objc_category *Category;
struct objc_category {
    char *category_name                          OBJC2_UNAVAILABLE; // 分類名
    char *class_name                             OBJC2_UNAVAILABLE; // 分類所屬的類名
    struct objc_method_list *instance_methods    OBJC2_UNAVAILABLE; // 實例方法列表
    struct objc_method_list *class_methods       OBJC2_UNAVAILABLE; // 類方法列表
    struct objc_protocol_list *protocols         OBJC2_UNAVAILABLE; // 分類所實現的協議列表
}

通過上面我們可以發現,這個結構體主要包含了分類定義的實例方法與類方法,其中instance_methods 列表是 objc_class 中方法列表的一個子集,而class_methods列表是元類方法列表的一個子集。
但這個結構體里面

根本沒有屬性列表,
根本沒有屬性列表,
根本沒有屬性列表。

Category的用途:

1.在不創建繼承類的情況下實現對已有類的擴展;
2.簡化類的開發工作(當一個類需要多個程序猿協同開發的時候,category可以將同一個類根據用途分別放在不同的源文件中,從而便于程序猿獨立開發相應的方法集合.)
3.將常用的相關方法進行分組;
4.在沒有源代碼的情況下可以用來修復BUG。
5.Category能對大型的類有效分解。通常一個大型類的方法可以根據某種邏輯或是相關性分解為不同的組,一個雷達代碼量越大,將這個類分解到不同的文件中就越顯得有用,每個文件分別是這個類的某些相關的方法的集合。當有多個開發者共同完成一個項目時,每個人所承擔的單獨的category的開發和維護。這樣就版本控制就更加簡單了,因為開發人員之間的工作沖突更少了。
6.當已知某個類庫的某個方法有BUG,我們無法直接修改源代碼的時候,可以使用Category來替代這個已有類中某個方法的實體,從而達到修復BUG的目的。然而卻沒有什么便捷的途徑可以去調用已有類中原有的那個被替換掉方法的實體了。Category通常作為一種組織架構代碼的工具來使用。

Category的注意:

1.分類用于給原有的類添加方法,因為分類在結構體指針中,沒有屬性列表,只有方法列表。所以<原則上講它只能添加方法,不能添加屬性(成員變量),實際上可以通過其它方法添加屬性(我們可以通過runtime手動添加setter/getter方法>
e.g:
在Category的.h文件聲明屬性:

 @property (nonatomic, copy) NSString *sex;

在Category的.m文件使用runtime實現setter/getter方法,這樣外部在訪問分類中的屬性時就不會奔潰,但是在使用_sex時還是會報錯:錯誤提示為:(Use of undeclared identifier '_sex')

static NSString *sexKey = @"SEXKEY";   //定義一個key值
@implementation Programmer (Category)

//運行時實現setter方法
- (void)sex:(NSString *)sex {
    objc_setAssociatedObject(self, & sexKey, sex, OBJC_ASSOCIATION_COPY);
}

//運行時實現getter方法
- (NSString *)sex {
    return objc_getAssociatedObject(self, & sexKey);
}

2.分類中可以寫@property,但是不會生成setter/getter方法,也不會生成實現以及私有的成員變量(編譯時會報警告)
3.可以在分類中訪問原有類.h中的屬性
4.如果分類中有和原類同名的方法,會優先調用分類中的方法,會忽略原有類的方法。同名方法調用的優先級為 分類>本類>父類,因此開發中盡量不要覆蓋原有類方法,除非是原有類方法有BUG。
5.如果多個分類中都有和原有類同名的方法,那么調用該方法的時候調用哪個分類中的方法由編譯器決定,編譯器會執行最后一個參與編譯的分類中的方法。

*******************************華麗麗的分割線*******************************

Extension解釋、定義

Extension是Category的一個特例。類擴展與分類相比只少了分類的名稱,所以也稱之為“匿名分類”
其實開發中,我們每天都在用,對于有些人來說就像是最熟悉的陌生人。
類擴展的格式:

@interface XXX ()
//私有屬性
//私有方法(如果不實現,編譯時會報警,Method definition for 'XXX' not found)
@end

Extension的作用

1.為一個類添加原來沒有的變量、方法、屬性
2.一般的類擴展寫到.m文件中
3.一般的私有屬性寫到.m文件中的類擴展中

Category (分類) 和 Extension (類擴展)的區別:

1.類別中原則上只能添加方法(能添加屬性的原因只是通過runtime解決無setter/getter的問題);
2.類擴展不僅可以增加方法還可以增加屬性,只是該屬性默認是@private(私有)類型的(應用范圍只能在自 身類,而不是子類或其他地方);
3.類擴展中聲明的方法沒有被實現,編譯器會報警,但是類別中的方法沒實現編譯器不會有任何警告。這是因為類擴展是在編譯階段被添加到類中,而類別是在運行時添加到類中的;
4.類擴展不能像類別那樣擁有獨立的實現部分(@implementation部分),也就是說:類擴展聲明的方法必須依托對應類的實現部分來實現;
5.定義在.m中的類擴展方法為私有方法,定義在.h中的類擴展方法為公有的。

總結這篇文章的目的一是為了自己的學習做記錄二是為讀者對分類、類擴展等常見的問題有個清晰的認識,以免在以后被人問起時回答的驢唇不對馬嘴。
RESOURCES

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容