分類(Category)
分類是OC中的特有語法,它是表示一個指向分類的結(jié)構(gòu)體的指針。原則上它只能增加方法,不能增加成員(實例)變量。其源碼組成
struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
///下面是原類的,和分類沒什么相關(guān)性,可不了解
method_list_t *methodsForMeta(bool isMeta) {
if (isMeta) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta) {
if (isMeta) return nil; // classProperties;
else return instanceProperties;
}
};
從分類的結(jié)構(gòu)可以看出,分類可以添加下面這些內(nèi)容
- 實例方法
- 類方法
- 協(xié)議
- 屬性(只生成了getter,setter方法的聲明,其實現(xiàn)和下劃線變量也就是
成員變量都沒有生成, 需要開發(fā)者自己去實現(xiàn),一般通過關(guān)聯(lián)對象添加成員變量)
一、分類的特點
- 運(yùn)行時決議,編譯好分類時,并沒有把方法添加到宿主類中,而是在運(yùn)行時通過memmove將方法移動到宿主類前面的(所以有相同的方法時,分類方法會優(yōu)先執(zhí)行)
分類添加的方法可以“覆蓋”原類方法(其實不是真的覆蓋刪除了,而是分類方法排在前面,后面的不執(zhí)行導(dǎo)致)
同名分類方法誰能生效取決于編譯順序(多個分類時,編譯順序是逆序的,所以當(dāng)分類實現(xiàn)了相同的方法時會優(yōu)先調(diào)用,后編譯的會覆蓋前面的。
名字相同的分類會引起編譯報錯
二、分類的應(yīng)用
- 聲明私有方法
- 將代碼進(jìn)行分類,分解體積龐大的類文件
- 將Framework的私有方法公開化
能否為分類添加"成員變量"?
三、通過關(guān)聯(lián)對象添加成員變量
///添加關(guān)聯(lián)對象
void objc_setAssociatedObject(id object, const void *key, id value, objec_associationPolicy policy)
///獲取關(guān)聯(lián)對象
id objc_getAssociatedObject(id object, const void *key)
//移除所有關(guān)聯(lián)對象
void objc_removeAssociatedObjects(id object);
簡單的例子
給UIView添加默認(rèn)顏色
#import <UIKit/UIKit.h>
@interface UIView (DefaultColor)
@property (nonatomic, strong) UIColor *defaultColor;
@end
#import "UIView+DefaultColor.h"
#import <objc/runtime.h>
static const char kDefaultColorKey; //只占用一個字節(jié),更節(jié)省內(nèi)存空間
//static const void *kDefaultColorKey = @"defaultColorKey";
@implementation UIView (DefaultColor)
- (void)setDefaultColor:(UIColor *)defaultColor{
objc_setAssociatedObject(self, &kDefaultColorKey, defaultColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIColor *)defaultColor{
return objc_getAssociatedObject(self, &kDefaultColorKey);
}
//- (void)setDefaultColor:(UIColor *)defaultColor{
// objc_setAssociatedObject(self, @selector(defaultColor), defaultColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//}
//
//- (UIColor *)defaultColor{
// return objc_getAssociatedObject(self, _cmd);
//}
@end
關(guān)聯(lián)對象原理:關(guān)聯(lián)對象其實并沒有在宿主類中添加成員變量,而是通過一個全局管理類AssociationsManager,將類和成員變量信息進(jìn)行綁定,保存在一個AssociationsHashMap表中的。
所有對象的關(guān)聯(lián)內(nèi)容都在同一個全局容器中。

screenshot_2022_12_16_14_59_43.png
擴(kuò)展(Extension)
一般用擴(kuò)展做什么?
- 聲明私有屬性
2.聲明私有方法 - 聲明私有成員變量
分類和擴(kuò)展的區(qū)別
擴(kuò)展是編譯時決議
只以聲明的形式存在,多熟情況下寄生于宿主.m文件中
不能為系統(tǒng)類添加擴(kuò)展
代理(Delegate)
通知(NSNotification)
是使用觀察者模式來實現(xiàn)的用于跨層傳遞消息的機(jī)制
傳遞方式為一對多
如何實現(xiàn)通知機(jī)制?
KVC
ARC
ARC是LLVM和Runtime協(xié)作的結(jié)果