OC中類別(Category)是什麼?
Category類別是Objective-C語言中提供的一個靈活的類擴展機制。類別用於在不獲悉、不改變原來代碼的情況下往一個已經存在的類中添加新的方法,只需要知道這個類的公開接口,而不需要知道類的源代碼。類別只能為已存在的類添加新的方法,而不能添加實例變量。類別擴展的新方法有更高的優先級,會覆蓋同名的原類的已有方法。
Category類別與其他特性的比較?
與繼承Inheritance的比較:
1.子類繼承是進行類擴展的另一種常用方法,當然基於子類繼承的擴展更加自由正式,既可以擴展屬性也可以擴展方法。類別可以在不獲悉、不改變原來代碼的情況下往裡面添加新的方法,但也只能添加方法,不能添加屬性,屬於功能上的擴展。類別擴展的優點是不需要創建一個新的類,而是在系統中已有的類上直接擴展,不需要更改系統類就可以添加並使用擴展方法。
2.相對於子類繼承擴展,類別的另一明顯優勢是實現了功能的局部化封裝,擴展的功能只會在本類被引用時看到。 假設原類為UIButton,現在要使用類別擴展一些用於模塊A的方法,那麼這些擴展方法就可以定義在一個叫做UIButton+A.h的頭文件中,只有在引用UIButton+A.h的地方,才能看到原UIButton類有模塊A添加的那些擴展方法,如果不需要模塊A的功能,不引用UIButton+A.h頭文件就看不到UIButton的那些擴展方法的存在。
與擴展Extension的比較:
Category類別和Extension擴展的明顯不同在於,後者可以添加屬性。另外後者添加的方法是必須要實現的。Extension可以認為是一個私有的匿名的Category。
類別有什麼作用和好處?類別的局限性和使用注意事項?
作用:
可以將類的實現分散到多個不同文件或多個不同框架中(擴充新的方法) 可以創建對私有方法的前向引用? 可以向對象添加非正式協議?局限性:
類別只能向原類中添加新的方法,且只能添加而不能刪除或修改原方法,不能向原類中添加新的屬性;
類別向原類中添加的方法是全局有效的而且優先級相對最高,如果和原類的方法重名,會無條件覆蓋掉原來的方法,造成難以發現的潛在危險,因此使用類別添加方法一定注意保證是單純的添加新方法,避免覆蓋原來的方法(可以通過添加該類別的方法前綴來防止沖突),否則原方法被類別覆蓋了,團隊中其他成員不知情的情況下用到這個被覆蓋的方法會出現意想不到的問題而難以察覺糾正。
Category類別和Extension類擴展的使用方法?
類別和擴展的區別我們已經知道了,最明顯的是類別不可以添加新屬性而類擴展可以。類別的使用方法很簡單,就是新建某個類的類別擴展文件,然後添加新的方法。而類擴展並不常用,只是常用在.m文件中的頭部進行頭文件的私有屬性變量補充,也就是所謂的類的continue區域,是將不想暴露給外部的一些變量定義在類擴展中。
創建類別或擴展文件:
為工程添加新文件並選擇Objective-C File:
填寫自定義的擴展名後綴,然後選擇文件類型,這裡選擇Category類別或者Extension擴展,最後選擇要擴展的已有類:
創建之後得到對應的類別文件:
添加新的擴展方法:
這裡以擴展NSString類的方法為例展示類別擴展的具體用法,分別添加一個類方法和實例方法,並在需要的地方調用:
類別頭文件方法聲明:
/* NSString+Category.h */ #import@interface NSString (Category) { // 不可以添加實例變量,編譯器會直接報錯! } // 實例變量被禁止,此處添加屬性變量是無意義的,定義的新的屬性變量編譯器不會為其自動生成存取方法, 編譯器也禁止了setter方法的手動實現,因為無法直接取得實例變量,無法為實例變量賦新值 //@property (nonatomic, copy) NSString *newString; /** * 擴展一個類方法 */ + (void)categoryClassMethodOfString; /** * 擴展一個實例方法 */ - (void)categoryInstanceMethodOfString; @end
類別方法實現,類別的方法可以不實現,不實現則不可調用否則會崩潰:
/* NSString+Category.m */ #import "NSString+Category.h" @implementation NSString (Category) + (void)categoryClassMethodOfString { NSLog(@"categoryClassMethodOfString"); } - (void)categoryInstanceMethodOfString { NSLog(@"categoryInstanceMethodOfString"); } @end
在需要的類中引入類別頭文件NSString+Category.h,然後即可調用新方法:
#import "NSString+Category.h" // 1.調用類別擴展的類方法 [NSString categoryClassMethodOfString]; // 2.調用類別擴展的實例方法 NSString *string = [NSString stringWithFormat:@""]; [string categoryInstanceMethodOfString];
類擴展的一般用法:
類擴展即類的.m文件中@implementation之前開始的部分,所謂的類的continue區域:
@interface class name () // ... @end
類擴展的作用本來是用於私有函數的前向聲明,但最新編譯器無需聲明也有相同的效果,因此私有方法可在.m文件中任意位置直接寫實現而無需在此處進行前向聲明,如果在此處聲明函數那麼一定要在後面進行實現,否則編譯器會給出警告。現在類擴展區域的作用主要是快速定義類的私有屬性,即將暴露給外部的屬性變量定義在頭文件中,而不想暴露給外部的屬性則直接定義在類擴展區域。
/* 類擴展區域 */ @interface ViewController () // 類擴展屬性(默認為private, 類外部不可訪問) @property (nonatomic,copy) NSString *extensionVariable; /** * 類擴展方法聲明,可省略,要在立刻在後面進行函數實現 */ - (void)extensionInstanceMethod; + (void)extensionClassMethod; @end