Category
1、Category的背景和概念
在日常開發中,經常需要對已有類進行功能上的擴展,在學習“類別”之前,常用的類擴展方式有以下三種:
-
原有類的修改
-
繼承
-
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的實現
-
通過單獨的.h聲明,在原有類的.m中導入。
-
直接在原有類的.m中使用。
category和Extension的區別
-
category原則上只能增加方法;而Extension方法和變量都可以。
-
Extension聲明方法沒有被實現,編譯器報警。category在運行時添加、Extension是編譯階段。
-
Extension沒有自己獨立的實現部分。
-
Extension是私有。