iOS開發的分類和擴充套件

左忠飛發表於2019-02-22

分類(Category):

概念

分類(Category)是OC中的特有語法,它是表示一個指向分類的結構體的指標。原則上它只能增加方法,不能增加成員(例項)變數。

  1. 分類中的可以寫@property, 但不會生成setter/getter方法, 也不會生成實現以及私有的成員變數(編譯時會報警告);
  2. 可以在分類中訪問原有類中.h中的屬性;
  3. 如果分類中有和原有類同名的方法, 會優先呼叫分類中的方法, 就是說會忽略原有類的方法。所以同名方法呼叫的優先順序為 分類 > 本類 > 父類。因此在開發中儘量不要覆蓋原有類;
  4. 如果多個分類中都有和原有類中同名的方法, 那麼呼叫該方法的時候執行誰由編譯器決定;編譯器會執行最後一個參與編譯的分類中的方法。
我們知道在一個類中用@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複製程式碼

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

擴充套件(Class Extension)

Extension是Category的一個特例。類擴充套件與分類相比只少了分類的名稱,所以稱之為“匿名分類”。
其實開發當中,我們幾乎天天在使用。對於有些人來說像是最熟悉的陌生人。

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

作用:

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


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

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


相關文章