Category與Extension

Category

1、Category的背景和概念

在日常開發中,經常需要對已有類進行功能上的擴展,在學習“類別”之前,常用的類擴展方式有以下三種:

  1. 原有類的修改

  2. 繼承

  3. protocol(協議)

針對以上三種擴展方式,

  • 第一種;

  • 第二種在繼承父類的同時,也擴展自己,包括(方法和變量)。但是在面向對象的開發原則中“優先使用組合慎用繼承”,因爲繼承在一定程度上破壞了封裝性、子類隨父類變動。

  • 第三種協議,主要是依靠實現類的具體方法實現,當擴展功能時,需要修改原有類,協議定義過多,實現類過於龐大。

那麼,在oc中,當我們想避免上述兩種擴展方式的缺點,又想只對現有類進行擴展些方法,並且不用去修改原有類以及使用它的地方的代碼,就用到了Category(類別)。

類別是OC的特有語法,可以通過在類上聲明和實現方法來擴展現有類的功能。原則上只能增加方法,不能增加成員變量。

2、category的聲明及實現

@interface 需擴展的類 (類別的名稱)
-(void)appendMethod;
@end

@implementation 需擴展的類 (類別的名稱)
-(void)appendMethod{
}
@end

3、category的使用

如果需要擴展一個類,定義好此類的category ,則可以通過高該類的對象直接調用category中的擴展方法。(可以擴展類方法),同時category中也可以訪問原有類.h中的屬性

#import "pson.h"

@implementation pson

-(void) run{
    NSLog(@"run");
}
+(void) jump{
    NSLog(@"jump");
}
@end

 

#import "pson+eat.h"

@implementation pson (eat)
-(void) eat{
    [self number];
    NSLog(@"eat");
}
+(void) drink{
    NSLog(@"drink");
}
@end
//在main方法中
pson *me = [[pson alloc] init];
        [me run];
        [me eat];
  

4、category擴展屬性(變量)

由於category本質上是個指向類型的結構體指針,在結構體中只有方法的列表,沒有屬性的列表,所以理論上只能增加方法不能增加屬性。

如何通過category來擴展屬性呢?

無法添加屬性的根本原因是:在category中@property聲明屬性,系統不會生成_成員變量和setter、getter。

解決方法:手動添加setter和getter方法,採用的就是:關聯引用(objc_setAssociatedObject和objc_getAssociatedObject)

其中,

objc_setAssociatedObject,接收4個參數:想關聯到數據的對象、獲取數據的鍵值、存儲引用的值、關聯的策略;

objc_getAssociatedObject,接收2個參數:關聯到數據的對象、鍵值

關聯策略

OBJC_ASSOCIATION_ASSIGN

指定值將被簡單賦值、沒有保留和釋放

OBJC_ASSOCIATION_RETAIN_NONATOMIC

指定值通過非線程安全的方式賦值並保留

OBJC_ASSOCIATION_COPY_NONATOMIC

指定值通過非線程安全的方式複製

OBJC_ASSOCIATION_RETAIN

指定值通過線程安全的方式賦值並保留

OBJC_ASSOCIATION_COPY

指定值通過線程安全的方式複製

#import "pson+eat.h"
#import "objc/runtime.h"
static NSString *key = @"personEatKey";

@implementation pson (eat)
-(void) eat{
    NSLog(@"eat");
}

-(void) setFood:(NSString *)food{
    objc_setAssociatedObject(self, &key, food, OBJC_ASSOCIATION_COPY);
}

-(NSString *) food{
    return objc_getAssociatedObject(self, &key);
}
@end
#import <Foundation/Foundation.h>
#import "pson.h"
#import "pson+eat.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        pson *me = [[pson alloc] init];
        [me eat];
        me.food = @"雞蛋";
        NSLog(@"%@",me.food);
        
    }
    return 0;
}

Extension

extension 是Category的特例,少了類別的名稱,是匿名分類。聲明私有方法和屬性的機制。具體實現在原有類的.m文件中。

1、extension的格式

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

2、extension的實現

  1. 通過單獨的.h聲明,在原有類的.m中導入。

  2. 直接在原有類的.m中使用。

 

category和Extension的區別

  1. category原則上只能增加方法;而Extension方法和變量都可以。

  2. Extension聲明方法沒有被實現,編譯器報警。category在運行時添加、Extension是編譯階段。

  3. Extension沒有自己獨立的實現部分。

  4. Extension是私有。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章