遇到一個問題,寫了一個分類,但原先類的屬性不夠用。添加一個屬性,調用的時候崩潰了,說是找不到getter、setter方法。查了下文檔發現,OC的分類允許給分類添加屬性,但不會自動生成getter、setter方法。有沒有解決方案呢?有,通過運行時建立關聯引用。接下來以添加一個這樣的屬性為例:
@property (nonatomic, copy) NSString *str;
1、引入運行時頭文件。
#import <objc/runtime.h>
2、在匿名分類或者頭文件中添加屬性。區別是:匿名分類中添加的是私有屬性,只在本類中可以使用,類的實例中不可以使用。頭文件中添加的在類的實例中也可以使用。
//分類的頭文件 @interface ClassName (CategoryName) //我要添加一個實例也可以訪問的變量所以就寫在這里了 @property (nonatomic, strong) NSString *str; @end //匿名分類 @interface ClassName () @end
3、在實現里面寫要添加屬性的getter、setter方法。
@implementation ClassName (CategoryName) -(void)setStr:(NSString *)str { objc_setAssociatedObject(self, &strKey, str, OBJC_ASSOCIATION_COPY); } -(NSString *)str { return objc_getAssociatedObject(self, &strKey); } @end
在setStr:
方法中使用了一個objc_setAssociatedObject
的方法,這個方法有四個參數,分別是:源對象,關聯時的用來標記是哪一個屬性的key(因為你可能要添加很多屬性),關聯的對象和一個關聯策略。
用來標記是哪一個屬性的key常見有三種寫法,但代碼效果是一樣的,如下:
//利用靜態變量地址唯一不變的特性 1、static void *strKey = &strKey; 2、static NSString *strKey = @"strKey"; 3、static char strKey;
關聯策略是個枚舉值,解釋如下:
enum { OBJC_ASSOCIATION_ASSIGN = 0, //關聯對象的屬性是弱引用 OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //關聯對象的屬性是強引用並且關聯對象不使用原子性 OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //關聯對象的屬性是copy並且關聯對象不使用原子性 OBJC_ASSOCIATION_RETAIN = 01401, //關聯對象的屬性是copy並且關聯對象使用原子性 OBJC_ASSOCIATION_COPY = 01403 //關聯對象的屬性是copy並且關聯對象使用原子性 };
4、完成后的整體代碼如下:
.h文件
//分類的頭文件 @interface ClassName (CategoryName) @property (nonatomic, strong) NSString *str; @end
.m文件
//實現文件 #import "ClassName + CategoryName.h" #import <objc/runtime.h> static void *strKey = &strKey; @implementation ClassName (CategoryName) -(void)setStr:(NSString *)str { objc_setAssociatedObject(self, & strKey, str, OBJC_ASSOCIATION_COPY); } -(NSString *)str { return objc_getAssociatedObject(self, &strKey); } @end