面試題
Q:分類中到底能否實現屬性?
A:
·1.如果把屬性理解爲通過方法訪問的實例變量,答案是不能,因爲分類不能爲類增加額外的實例變量。會提示黃色警告,使用的時候運行到這裏會crash。
·2.如果屬性只是一個存取方法,那麼分類是可以實現屬性的。
這篇文章主要講的是使用runtime裏面的AssociatedObject關聯對象的方法來模擬『屬性』的存取方法,也就是 objc_getAssociatedObject 以及 objc_setAssociatedObject兩個方法 。
id objc_getAssociatedObject(id object, const void *key);
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
在使用這兩個方法之前需要在分類裏面導入#import <objc/runtime.h> 或者 #import <objc/message.h> //這兩種都可以。
說一下每個參數的含義:
- 第一個方法的兩個參數:
1.源對象(self)
2.關聯時用來標記是哪一個屬性的key
- 第二個方法的參數:
1.源對象(self)
2.關聯時用來標記是哪一個屬性的key
3.關聯的對象
4.關聯策略(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
關聯策略是個枚舉值
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
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並且關聯對象使用原子性
};
名稱 | 對應的修飾詞 |
---|---|
objc_AssociationPolicy | modifier |
OBJC_ASSOCIATION_ASSIGN | assign |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | nonatomic, strong |
OBJC_ASSOCIATION_COPY_NONATOMIC | nonatomic, copy |
OBJC_ASSOCIATION_RETAIN | atomic, strong |
OBJC_ASSOCIATION_COPY | atomic, copy |
也就是你定義屬性的時候給的修飾詞,譬如:
@property(nonatomic, strong)UIView *loadView;
上面這個屬性關聯策略也就是 OBJC_ASSOCIATION_RETAIN_NONATOMIC
@property(nonatomic, copy)NSString *name;
關聯策略也就是 OBJC_ASSOCIATION_COPY_NONATOMIC
#import "UIView+lf.h"
#import <objc/runtime.h>
static NSString *loadViewKey = @"loadViewKey"; //loadViewKey的key
@implementation UIView (lf)
-(void)setLoadView:(UIView *)loadView{
objc_setAssociatedObject(self, &loadViewKey, loadView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(UIView *)loadView{
return objc_getAssociatedObject(self, &loadViewKey);
}
@end
有時候我們也會看到有人用下面的寫法
#import "UIView+lf.h"
#import <objc/runtime.h>
static NSString *nameKey = @"nameKey"; //name的key
@implementation UIView (lf)
-(NSString *)name{
return objc_getAssociatedObject(self, _cmd);
}
-(void)setName:(NSString *)name{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
這裏的 _cmd 代指當前方法的選擇子,也就是 @selector(name)。第二句代碼中出現 @selector(name),這裏它就調用第一句代碼了, @selector直接返回SEL,則獲取到name的方法名,則爲第一句代碼返回的值.