分類(category)
應用場景
在我們開發(fā)中經(jīng)常會有這樣的問題:
- 多個人同時維護同一個類 ,彼此之間交叉修改同一個文件,導致沖突以及文件臃腫。
- 想給已經(jīng)封裝好的類(或者是系統(tǒng)類,第三方庫的類)增加方法,而又不想使用繼承后的子類。
- 希望拆分一個過于龐大的類。
分類(category)可以很好的解決這些問題。
介紹
分類是OC的一種語法,他可以在一個新的文件中為一個即有的類添加新的方法(理論上不能添加新的屬性)
我們?yōu)镹SObject添加一個分類名為haha的分類,并在這個分類中為NSObject添加一個laugh方法:
.h
@interface NSObject (haha)
-(void)laugh;
@end
.m
#import "NSObject+haha.h"
@implementation NSObject (haha)
-(void)laugh
{
NSLog(@"hahahahahaha");
}
@end
在程序入口處,我們只需要引用這個分類,就可以直接調(diào)用分類里的方法了:
#import "NSObject+haha.h"
NSObject * obj = [NSObject new];
[obj laugh];
源碼分析
我們在runtime.h中可以找到category的運行時結(jié)構(gòu)體:
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;
}
我們可以看到,在運行時,分類的結(jié)構(gòu)體里有分類名,原類名,實例方法列表,類方法列表,協(xié)議列表。但是并沒有變量列表。
這就是分類中是無法添加變量的原因。
如果非要為分類添加屬性,我們可以用動態(tài)添加屬性(Associated Object)技術間接實現(xiàn)
我們在haha分類中為NSObject添加一個name屬性:
.h
@interface NSObject (haha)
@property(nonatomic,copy)NSString *name;
-(void)laugh;
@end
這時在.m文件中系統(tǒng)給我們警告,讓我們實現(xiàn)name方法和setName方法,因為,在分類中定義屬性,系統(tǒng)并不會為我們生成get,set方法,也不會生成實例變量。
我們需要利用動態(tài)添加屬性(Associated Object)手動編寫get和set方法:
#import "NSObject+haha.h"
#import <objc/runtime.h>
static NSString *nameKey = @"nameKey";
@implementation NSObject (haha)
-(void)laugh
{
NSLog(@"hahahahahaha");
}
-(NSString *)name
{
return objc_getAssociatedObject(self, &nameKey);
}
-(void)setName:(NSString *)name
{
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
通過這種方式,我們看起來就為分類添加了一個name屬性,但是任然不能訪問_name實例變量,因為它并不存在。
小細節(jié)
- 分類中可以使用原類的.h中的屬性,方法。
- 如果分類中有原類的同名方法,那么,會覆蓋原類方法。同名方法優(yōu)先級:分類>原類>父類
- 如果多個分類有同名方法,那么執(zhí)行最后加入編譯的分類的方法。
類擴展(Class Extension)
類擴展介紹
類擴展其實我們平時使用非常多,只是可能很多同學不知道,那個就是類擴展而已,我們平時創(chuàng)建控制器時IDE就會幫我們在.m文件里自動生成一個類擴展,供我們寫一些私有的方法和屬性:
@interface ViewController ()
@end
類擴展最常見的使用場景就是在.m中定義私有的屬性和方法。
類擴展的幾個特點
與分類不同的是類擴展是可以添加屬性的,并且會自動生成get方法,set方法,實例變量。
類擴展可以定義在.m 中,其中的屬性方法為私有,也可以定義在.h中,它的屬性和方法為共有。
類擴展的中方法的實現(xiàn),必須在原類的.m文件中。