分類(category)和類擴展(extension)

分類(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文件中。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容