本文已經添加到專輯:《完全弄懂OC》。 歡迎加入個人QQ羣:661461410
,一塊兒探討iOS底層原理。objective-c
咱們知道在一個類中增長一個屬性,編譯器會幫咱們作3件事,好比,咱們給Person
這個類增長一個屬性age
,編譯以後,類中會增長一個成員變量_age
, 增長get方法和set方法的生命與實現 -(int)age
和 -(void)setAge:(int)age
。多線程
可是咱們在分類裏面聲明一個屬性,會幫咱們聲明兩個方法set, get。 但不會生成實現,也不會產生成員變量。因此咱們不能直接給Category添加成員變量,可是能夠間接實現Category有成員變量的效果。函數
下面代碼中,咱們爲person的分類增長了一個age屬性,咱們經過聲明一個全局變量_age,將age的值存儲到_age中。ui
@interface Person (Test)
@property (nonatomic, assign) int age;
@end
@implementation Person (Test)
int _age;
- (void)setAge:(int)age {
_age = age;
}
-(int)age {
return _age;
}
@end
複製代碼
但,這種方式有致命的肯定,就是多個實例對象共用_age,致使數據錯誤。atom
#import "Person+Test.h"
@implementation Person (Test)
NSMutableDictionary *_ageDic;
+ (void)load {
_ageDic = [[NSMutableDictionary alloc] init];
}
- (int)age {
NSString *selfKey = [NSString stringWithFormat:@"%p", self];
return [[_ageDic valueForKey: selfKey] intValue];
}
- (void)setAge:(int)age {
NSString *selfKey = [NSString stringWithFormat:@"%p", self];
[_ageDic setValue:@(age) forKey:selfKey];
}
@end
複製代碼
使用字典來存儲值解決上一種方法中多個對象致使數據錯亂的問題,但它也有一些問題,以下:spa
#import "Person+Test.h"
#import <objc/runtime.h>
@implementation Person (Test)
- (int)age {
return [objc_getAssociatedObject(self, @selector(age)) intValue];
}
- (void)setAge:(int)age {
objc_setAssociatedObject(self, @selector(age), @(age), OBJC_ASSOCIATION_ASSIGN);
}
@end
複製代碼
這種方式,咱們使用runtime提供的兩個方法objc_setAssociatedObject
和 objc_setAssociatedObject
來分別設置和獲取屬性值。就objc_setAssociatedObject
而言其接受三個參數:線程
id,表示爲當前對象關聯屬性。code
key,關聯屬性對應的惟一key,這裏咱們使用get方法的函數地址值。orm
value,key對應的值。cdn
objc_AssociationPolicy, 存儲策略。有5個取值,根據屬性的類型選擇對應的內存存儲策略。
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
關聯對象的底層實現涉及到了4個類,分別是:
其實現結構以下:
其中 AssociationsHashMap
中 disguised_ptr_t
表示對象,AssociationMap
中的 void *
表示 key
。ObjectAssociation
中包含value
和存儲策略。
咱們以上面的Person對象爲例,圖示一下總體的結構。
經過上面的分析,咱們回答一下開頭的問題:
分類不能夠直接添加屬性,但能夠間接添加,最優雅的方式是經過關聯對象進行屬性與分類的綁定。
那麼,留一個問題,你認爲關聯對象須要手動釋放嗎? 在類銷燬的時候,須要釋放其經過關聯對象綁定的屬性嗎?