Category與Extension
阿新 • 來源:網路 • 發佈:2021-02-10
技術標籤:iOS開發iosobjective-c
1. Category
1.1 定義與特點
- ObjC語言的一個靈活的類擴充套件機制,可以在不知道原有程式碼的基礎上向一個已存在類新增新的方法
- 不能修改、刪除已有方法,對擴充套件開放、對修改封閉,體現了面向物件的OCP原則,降低了程式碼的耦合度。
- 類別擴充套件的新方法有更高優先順序,會覆蓋類中已有的同名方法;宣告的方法可以不實現,但不實現時不可以呼叫此方法
1.2 關於新增變數
- 只能新增擴充套件方法,不能新增成員變數
- 因為
Category是執行期決議,執行時物件的記憶體佈局已經確定,objc_class結構體大小已確定,無法再新增成員變數 - 在
Category中定義了property後,編譯器只為其聲明瞭存取方法,但沒有實現;也沒有合成加下劃線的例項變數名,導致無法訪問例項變數名
1.3 用runtime為屬性新增存取方法
- 可以使用
runtime提供的關聯物件方法,動態的為property實現getter和setter,以實現setter為例
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
- key是一個void指標
- value是關聯物件,是
id型別(編譯時型別不確定,視為任意Object型別) - policy指定一個記憶體管理策略來處理關聯物件,
OBJC_ASSOCIATION_ASSIGN:被關聯物件釋放時,關聯物件不會被釋放
OBJC_ASSOCIATION_COPY、OBJC_ASSOCIATION_COPY:關聯物件會被釋放
- 擴充套件
NSString類的方法為例,擴充套件屬性、例項方法和類方法,使用runtime實現屬性的getter和setter,程式碼如下:
// NSString+Category.h
#import <Foundation/Foundation.h>
@interface NSString (Category) {
/*不可新增成員變數*/
}
@property(nonatomic,copy) NSString *newString;
//擴充套件的例項方法和類方法
+(void)categoryClassMethod;
-(void)categoryInstanceMethod;
@end
// NSString+Category.m
#import "NSString+Category.h"
#import <objc/runtime.h>
@implementation NSString (Category)
//runtime強行實現newString的getter和setter
-(NSString *)newString {
return objc_getAssociatedObject(self, @"newString");
}
-(void)setNewString:(NSString *)newString {
objc_setAssociatedObject(self, @"newString", newString, OBJC_ASSOCIATION_COPY);
}
//擴充套件的例項方法和類方法
+(void)categoryClassMethod {
NSLog(@"這是擴充套件的類方法");
}
-(void)categoryInstanceMethod {
NSLog(@"這是擴充套件的例項方法");
}
@end
- 在主函式中呼叫
// main.m
#import <Foundation/Foundation.h>
#import "NSString+Category.h"
int main(int argc, const char * argv[]) {
NSString *string = [[NSString alloc] init];
//runtime實現的getter和setter
string.newString = @"你好";
NSLog(@"%@",string.newString);
//擴充套件的類方法和例項方法
[NSString categoryClassMethod];
[string categoryInstanceMethod];
return 0;
}
- 執行結果如下

2. Extension
2.1 位置
- 在類的.m檔案中
@implementation之前的地方,即類的continuous區域
2.2 為啥要用
- 類擴充套件的作用本來是私有方法的前向宣告,但最新的編譯器可以在.m檔案中任意位置寫實現而無需宣告,如果聲明瞭就一定要實現
- 現在
Extension區域的作用主要是定義類的私有屬性,將暴露給外部的屬性、變數和方法定義在.h檔案中,不想暴露的直接定義在.m檔案的Extension區 - 私有並不是絕對的,仍然可以使用
KVC和runtime暴力訪問私有屬性和變數、使用runtime暴力訪問私有方法
2.2 關於新增變數
- Extension是編譯器決議的,它就是類的一部分,因此可以新增成員變數
- Category執行期決議,不能新增成員變數
/*類擴充套件區域*/
@interface extensionClass()
/* 類擴充套件屬性,類外部不可訪問*/
@property(nonatomic, copy) NSString* extensionVariable;
/* 類擴充套件方法宣告,可省略,若聲明瞭就得在後面實現 */
-(void)extensionInstanceMethod;
+(void)extensionClassMethod;
