分類(Category)和擴(kuò)展(Extension)

分類(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)對象添加成員變量)

一、分類的特點

  1. 運(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ò)展做什么?

  1. 聲明私有屬性
    2.聲明私有方法
  2. 聲明私有成員變量

分類和擴(kuò)展的區(qū)別
擴(kuò)展是編譯時決議
只以聲明的形式存在,多熟情況下寄生于宿主.m文件中
不能為系統(tǒng)類添加擴(kuò)展

代理(Delegate)

通知(NSNotification)
是使用觀察者模式來實現(xiàn)的用于跨層傳遞消息的機(jī)制
傳遞方式為一對多

如何實現(xiàn)通知機(jī)制?

KVC

ARC
ARC是LLVM和Runtime協(xié)作的結(jié)果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容