分類Category、擴展Extension 分析

前言

引用 iOS分類(category),類擴展(extension)—史上最全攻略

分類 Category

概念

分類 CatgegoryOC 中特有的語法,他表示一個指向分類的結構體指針。原則上,分類只能增加方法,不能添加變量。但是可以通過 runtime 實現變量的添加。

源碼

runtime.h 中實現:

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; // 分類所實現的協議列表
}

objc-runtime-new.h 中實現:

struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};

以上,可以看出,分類中既有實例方法、類方法的存儲列表,也有實例屬性、類屬性的列表。但是變量列表僅僅定義了,并未做返回設置。個人猜測,這也是為啥么添加成員變量,訪問會崩潰的原因

注意:

  • 分類中無法添加成員變量,即下劃線變量。
  • 分類中可以寫 @property 屬性,但是不會生成默認的 settergetter 方法,也不會生成實現,以及私有的成員變量,編譯時警告。
  • 可以在分類中訪問主類 .h 中的屬性、方法,但是無法訪問下劃線屬性。
  • 如果分類中右主類同名方法,調用時優先執行分類中的方法。并不是覆蓋,以為主類中的方法依然在,只是查找到指定的方法后,就不再繼續查找了。方法調用順序 分類 > 主類 > 父類
  • 如果多個分類都有同名方法,則執行順序由編譯器決定。

分類格式

@interface 待擴展的類(分類的名稱)
@end

@implementation 待擴展的名稱(分類的名稱)
@end

舉例:

//  Programmer+Category.h文件中
@interface Programmer (Category)

@property(nonatomic,copy) NSString *nameWithSetterGetter;           //設置setter/getter方法的屬性

@property(nonatomic,copy) NSString *nameWithoutSetterGetter;        //不設置setter/getter方法的屬性(注意是可以寫在這,而且編譯只會報警告,運行不報錯)

- (void) programCategoryMethod;                                     //分類方法

@end

//  Programmer+Category.m文件中

下面通過 runtime 實現分類添加屬性的功能:

#import <objc/runtime.h>

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

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

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

@end

類擴展 Class Extension

ExtensionCategory 的一個特例。類擴展因為不包含分類名稱,又稱 匿名分類

開發中,我們幾乎天天在使用類擴展。

類擴展格式:

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

類擴展作用:

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

分類 VS 擴展

  1. 分類中原則上只能添加方法。可通過 runtime 添加屬性不能添加成員變量。
  2. 類擴展可以添加屬性、方法、成員變量。但默認是 private 類型的。
  3. 分類中,如果方法、屬性沒有實現,會有警告。擴展則不會有警告。因為。擴展是在編譯階段加到類中,而類別則是運行時加到類中
  4. 擴展沒有單獨實現的部分,即 @implementation。需要依賴主類 .m 文件實現定義的功能。
  5. .h 中類擴展方法、屬性是對外共有的,.m 中類擴展中聲明的,都是私有的。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。