1. 程式人生 > 其它 >iOS 分類(Category)和擴充套件(Extension)

iOS 分類(Category)和擴充套件(Extension)

日常開發中用Extension做什麼?

Extension:擴充套件, 延展, 匿名分類;放在.m檔案中;
宣告私有屬性; (不對子類暴露)
宣告私有方法;
宣告私有成員變數;

分類(Category)和擴充套件(Extension)區別?
分類(Category)擴充套件(Extension)
執行時決議 編譯時決議
有單獨的.h.m檔案 以宣告的方式存在, 寄生於宿主類的.m檔案
可以為系統類新增分類 不能為系統類新增擴充套件
看不到原始碼的類可以新增分類 沒有.m原始碼的類無法為其新增擴充套件
分類(Category):

概念
分類(Category)是OC中的特有語法,它是表示一個指向分類的結構體的指標。原則上它只能增加方法,不能增加成員(例項)變數。
注意:
1.分類是用於給原有類新增方法的,因為分類的結構體指標中,沒有屬性列表,只有方法列表。所以< 原則上講它只能新增方法, 不能新增屬性(成員變數),實際上可以通過其它方式新增屬性> ;
2.分類中的可以寫@property, 但不會生成setter/getter方法, 也不會生成實現以及私有的成員變數(編譯時會報警告);
3.可以在分類中訪問原有類中.h中的屬性;
4.如果分類中有和原有類同名的方法, 會優先呼叫分類中的方法, 就是說會忽略原有類的方法。所以同名方法呼叫的優先順序為 分類 > 本類 > 父類。因此在開發中儘量不要覆蓋原有類;
5.如果多個分類中都有和原有類中同名的方法, 那麼呼叫該方法的時候執行誰由編譯器決定;編譯器會執行最後一個參與編譯的分類中的方法。

//分類格式:
@interface 待擴充套件的類(分類的名稱)
@end

@implementation 待擴充套件的名稱(分類的名稱)
@end
//實際程式碼
//  Programmer+Category.h檔案中
@interface Programmer (Category)

@property(nonatomic,copy) NSString *nameWithSetterGetter;           //設定setter/getter方法的屬性

@property(nonatomic,copy) NSString *nameWithoutSetterGetter;        //不設定setter/getter方法的屬性(注意是可以寫在這,而且編譯只會報警告,執行不報錯)

- (void) programCategoryMethod;                                     //分類方法

@end

//  Programmer+Category.m檔案中
為什麼在分類中宣告屬性時,執行不會出錯呢?既然分類不讓新增屬性,那為什麼我寫了@property仍然還以編譯通過呢?

接下來我們探究下分類不能新增屬性的實質原因:
我們知道在一個類中用@property宣告屬性,編譯器會自動幫我們生成成員變數和setter/getter,但分類的指標結構體中,根本沒有屬性列表。所以在分類中用@property宣告屬性,既無法生成成員變數也無法生成setter/getter。
因此結論是:我們可以用@property宣告屬性,編譯和執行都會通過,只要不使用程式也不會崩潰。但如果呼叫了_成員變數和setter/getter方法,報錯就在所難免了。
那接下來我們繼續思考:
既然報錯的根本原因是使用了系統沒有生成的setter/getter方法,可不可以在手動新增setter/getter來避免崩潰,完成呼叫呢?
其實是可以的。由於OC是動態語言,方法真正的實現是通過runtime完成的,雖然系統不給我們生成setter/getter,但我們可以通過runtime手動新增setter/getter方法。那具體怎麼實現呢?

#import <objc/runtime.h>

static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey";   //定義一個key值
@implementation Programmer (Category)

//執行時實現setter方法
- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {
        objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY);
}

//執行時實現getter方法
- (NSString *)nameWithSetterGetter {
    return objc_getAssociatedObject(self, &nameWithSetterGetterKey);
}

@end
//通過runtime實現了setter/getter
    programmer.nameWithSetterGetter = @"有setter/getter";    //呼叫setter,成功
    NSLog(@"%@",programmer.nameWithSetterGetter);            //呼叫getter,成功
//    NSLog(@"%@",_nameWithSetterGetter); //這是呼叫_成員變數,錯誤提示為:(Use of undeclared identifier '_nameWithSetterGetter')

但是注意,以上程式碼僅僅是手動實現了setter/getter方法,但呼叫_成員變數依然報錯。

類擴充套件(Class Extension)

Extension是Category的一個特例。類擴充套件與分類相比只少了分類的名稱,所以稱之為“匿名分類”。

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

作用:
為一個類新增額外的原來沒有變數,方法和屬性
一般的類擴充套件寫到.m檔案中
一般的私有屬性寫到.m檔案中的類擴充套件中

類別與類擴充套件的區別:

①類別中原則上只能增加方法(能新增屬性的的原因只是通過runtime解決無setter/getter的問題而已);
②類擴充套件不僅可以增加方法,還可以增加例項變數(或者屬性),只是該例項變數預設是@private型別的(
用範圍只能在自身類,而不是子類或其他地方);
③類擴充套件中宣告的方法沒被實現,編譯器會報警,但是類別中的方法沒被實現編譯器是不會有任何警告的。這是因為類擴充套件是在編譯階段被新增到類中,而類別是在執行時新增到類中。
④類擴充套件不能像類別那樣擁有獨立的實現部分(@implementation部分),也就是說,類擴充套件所宣告的方法必須依託對應類的實現部分來實現。
⑤定義在 .m 檔案中的類擴充套件方法為私有的,定義在 .h 檔案(標頭檔案)中的類擴充套件方法為公有的。類擴充套件是在 .m 檔案中宣告私有方法的非常好的方式。

連結:https://www.jianshu.com/p/f1f0082c0b5b
連結:https://www.jianshu.com/p/9e827a1708c6



作者:清風_____
連結:https://www.jianshu.com/p/b344aa23268f
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。