使用AssociatedObject在分類中添加屬性

面試題

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的方法名,則爲第一句代碼返回的值.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章