KVO
- KVO 全程是key-value Observing,俗稱“鍵值監聽”,可以用于監聽某個對象屬性值的改變
- 利用runtimeAPI動態生成一個子類,并且讓instance的ISA 指向這個全新的子類
當修改instance對象的屬性時 ,會在新的子類中的set方法里調用Foundation的_NSSetxxxvaluedAndNotify函數
然后調用 wilChangeValuedForKey: ——>父類原來的setter——>didChangeValueforkey 方法 ,此方法內部會出發監聽器(Observer)的監聽方法(ObserverValueForKeyPath:ofObject:change:context)
KVC
key-value codeing 鍵值編碼 ,可以通過一個key,訪問某個屬性
-
setValue:forKey:的原理
image.png -
valueForKey:的原理
image.png
Category實現原理
- category編譯之后的底層結構是struct_category_t ,里面存儲著對象方法、屬性、類方法、協議信息
- 在程序運行的時候,runtime會將category的數據,合并到類信息中(類對象、元類對象中)
即runtime 把category的方法、屬性、協議等合并到一個大數組總,后面參與編譯的category數據,會在數組的前面;合并后的分類數據(方法、協議、屬性),插入到類原來數據的前面
Category和Class Extension的區別是什么?
Class Extension在編譯的時候,它的數據就已經包含在類信息中
Category是在運行時,才會將數據合并到類信息中
Loda 和 initialize 方法
######## load
- load方法會在runtime加載類、分類的時候調用
- 每個類、分類的load方法在程序運行過程中只調用一次
- 調用順序:
- 1 : 先調用類的load 方法
- 按照編譯先后順序調用(先編譯,先調用)
- 調用子類的load方法之前會先調用父類的load方法
- 2 : 在調用分類的load方法
- 先編譯,先調用(按照編譯的先后順序)
######## initialize
- initialize方法會在
類
第一次接受消息的時候調用 - 調用順序: 先調用父類的+initialize方法,在調用子類的+initialize方法(先初始化父類,在初始化子類,每個類之只會初始化一次)
- +initialize和load方法的區別: +initialize是通過objc_msgSend進行調用的。若果子類沒有實現+initialize,會調用父類的+initialize(所以父類的initialize可能會被調用多次),如果分類實現了+initialize,就會覆蓋本身的+initialize調用
load、initialize方法的區別什么?
1.調用方式
1> load是根據函數地址直接調用
2> initialize是通過objc_msgSend調用
2.調用時刻
1> load是runtime加載類、分類的時候調用(只會調用1次)
2> initialize是類第一次接收到消息的時候調用,每一個類只會initialize一次(父類的initialize方法可能會被調用多次)
load、initialize的調用順序?
1.load
1> 先調用類的load
a) 先編譯的類,優先調用load
b) 調用子類的load之前,會先調用父類的load
2> 再調用分類的load
a) 先編譯的分類,優先調用load
2.initialize
1> 先初始化父類
2> 再初始化子類(可能最終調用的是父類的initialize方法)
objc_associationPolicy
- 常用方法
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)
static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)
使用屬性名作為key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");
使用get方法的@selecor作為key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
// 隱式參數
// _cmd == @selector(name)
return objc_getAssociatedObject(self, _cmd);
}
- (void)setWeight:(int)weight
{
objc_setAssociatedObject(self, @selector(weight), @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight
{
// _cmd == @selector(weight)
return [objc_getAssociatedObject(self, _cmd) intValue];
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @selector(name));
}
- (int)weight
{
return [objc_getAssociatedObject(self, @selector(weight)) intValue];
}
#define MJNameKey @"name"
#define MJWeightKey @"weight"
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, MJNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, MJNameKey);
}
- (void)setWeight:(int)weight
{
objc_setAssociatedObject(self, MJWeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight
{
return [objc_getAssociatedObject(self, MJWeightKey) intValue];
}
static const void *MJNameKey = &MJNameKey;
static const void *MJWeightKey = &MJWeightKey;
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, MJNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, MJNameKey);
}
- (void)setWeight:(int)weight
{
objc_setAssociatedObject(self, MJWeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight
{
return [objc_getAssociatedObject(self, MJWeightKey) intValue];
}
static const char MJNameKey;
static const char MJWeightKey;
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, &MJNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, &MJNameKey);
}
- (void)setWeight:(int)weight
{
objc_setAssociatedObject(self, &MJWeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight
{
return [objc_getAssociatedObject(self, &MJWeightKey) intValue];
}
image.png
- 關聯對象并不是存儲在被關聯對象本身內存中
- 關聯對象存儲在全局統一的一個AssociationManage中
-
設置關聯對象為nil,就相當于移除關聯對象
image.png