1. 程式人生 > >2-3 iOS 分類(Category)& 類擴充套件(Extension)

2-3 iOS 分類(Category)& 類擴充套件(Extension)

     分類(Category):

        分類是OC中的一個特有語法,它表示一個指向分類結構體的指標。一般情況下,我們只能新增給分類增加方法,而不能增加例項變數(成員變數)。

      分類的格式:

@interface 待擴充套件的類(分類的名稱)
@end

@implementation 待擴充套件的類(分類的名稱)
@end

      分類的使用場景:

        我們知道,給一個A類新增方法,簡單粗暴的方式就是直接在A類在.h中宣告,.m中實現該方法。但是這樣做,有時候不便於專案的管理和移植,試想,如果一個類有雜七雜八幾十個不同的方法糅合在一個.h中。要是以後我們想要呼叫其中某一個方法,還得把整個移植過來,或者把方法扣出來。這多惱火。     蘋果為了解決這些問題,特地引入了分類這個概念。我們可以專門用一個資料夾管理這些分類。比如UIImage資料夾下面,UIImage+GIF,UIImage+Cache。。。等等。很直觀,也更便於專案的管理與移植。

      為分類新增屬性:

        直接給分類新增@property,編譯器只會給你警告。但是如果你呼叫這個屬性,就會報錯。這是為什麼呢?        首先,我們來看看分類的原始碼組成,原始碼位於objc/runtime.h中。        
struct objc_category {
    char * _Nonnull category_name                            OBJC2_UNAVAILABLE; //分類名稱
    char * _Nonnull class_name                               OBJC2_UNAVAILABLE; //要擴充套件的類名
    struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE; //例項方法列表
    struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE; //類方法列表
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE; //分類實現的協議
}
        我們發現,分類所指向的結構體中根本就沒有屬性列表。所以,就算是你強行用@property,編譯器也不會給你自動生成setter/getter方法,也不會生成私有成員變數。         但是,有些情況下,我們在給分類新增的方法中,如果有屬性存在的話,會便利很多。比如,我想給一個UIButton類擴大點選區域,需要上下左右四個可變數值,用屬性的話要便利很多。但如何去給分類新增屬性呢?         如果研究過runtime相關的程式碼,相信你肯定知道關聯物件這一說法。如果你暫時還不瞭解,可以看看我之前的一篇博文runtime動態關聯物件,在此我就只簡單描述一下。定義靜態變數,用其地址作為關聯物件的key
#import <objc/runtime.h>
@implementation UIButton (EnlargeTouchArea)


static char topNameKey;
static char rightNameKey;
static char bottomNameKey;
static char leftNameKey;
設定關聯物件
- (void)addIncreaseTapAreaWithTop:(CGFloat)top buttom:(CGFloat)buttom left:(CGFloat)left right:(CGFloat)right {

    objc_setAssociatedObject(self, &kTopNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kRightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kButtomNameKey, [NSNumber numberWithFloat:buttom], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kLeftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);

}

獲取關聯物件

    NSNumber *top = objc_getAssociatedObject(self, &kTopNameKey);
    NSNumber *right = objc_getAssociatedObject(self, &kRightNameKey);
    NSNumber *buttom = objc_getAssociatedObject(self, &kButtomNameKey);
    NSNumber *left = objc_getAssociatedObject(self, &kLeftNameKey);

以上,就是如何動態為分類新增屬性。

     類擴充套件(Extension):

        類擴充套件其實也是分類的一種,我們應該說是時時刻刻都在打交道。類擴充套件和分類的區別就在於有沒有分類的名稱,以及類擴充套件是編譯期屬性,分類屬於執行時屬性。

      類擴充套件的實現:

@interface ExtionsionClass
@property (nonatomic,copy) NSString *name;
- (void)eat;
@end
        使用類擴充套件注意兩點:    1.一般類擴充套件寫在依託的對應類的.m中,私有屬性寫到擴充套件中。

    2.類擴充套件中方法的實現,需要在依託的對應類的.m中實現(區別於分類,沒有@implementation部分)。如果沒有實現已經聲明瞭的方法,編譯器會報警(區別於分類,分類這種情況不會報警告。這就是我說的編譯期和執行時的差別)。

    這兩種如何合理使用,看各人的愛好以及對應業務的處理吧。