久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

iOS 讀懂runtime基礎(chǔ)(一)

 印度阿三17 2020-03-06

目錄

前言

本文會詳細(xì)描述Objective-C運(yùn)行時(shí)的各對象數(shù)底層據(jù)結(jié)構(gòu),、類和原類,、消息傳遞與轉(zhuǎn)發(fā)、動態(tài)方法等技術(shù)方案. 文中底層代碼實(shí)現(xiàn)均來自Apple open source; 本文篇幅較長, 文中描述加之有個(gè)人的一點(diǎn)理解, 主要用作記錄和學(xué)習(xí)之用, 文筆粗陋, 技術(shù)菜雞, 如有錯(cuò)誤或不妥之處, 萬望各位大佬不吝指教, 不勝感激!

runtime是什么

Objective-C runtime是一個(gè)動態(tài)運(yùn)行庫, 它給Objective-C語言的動態(tài)性提供了支撐. 所有的應(yīng)用都會鏈接到該運(yùn)行時(shí)庫.

The Objective-C runtime is a runtime library that provides support for the dynamic properties of the Objective-C language, and as such is linked to by all Objective-C apps. Objective-C runtime library support functions are implemented in the shared library found at /usr/lib/libobjc.A.dylib.

三個(gè)重要概念

在下述講述過程中, 你應(yīng)該注意三個(gè)非常重要的概念.即Class,、SEL,、IMP, 在這里我先把他們列出來, 后面我們會一一的深入講到其內(nèi)部結(jié)構(gòu)和之間的關(guān)系.

typedef struct objc_class *Class;
 
typedef struct objc_object {
 
    Class isa;
 
} *id;
 
typedef struct objc_selector   *SEL;   
 
typedef id (*IMP)(id, SEL, ...);

一 各主要對象數(shù)據(jù)結(jié)構(gòu)

1 objc_object

objc_object表示實(shí)例對象底層是結(jié)構(gòu)體, 內(nèi)部有一個(gè)私有的isa指針, 該指針指向了其類對象

struct objc_object {
private:
    isa_t isa;
...
// isa相關(guān)操作
// 弱引用, 關(guān)聯(lián)對象, 內(nèi)存管理等等相關(guān)的操作
// 都是在此結(jié)構(gòu)體中, 篇幅太長, 不再全部貼出
}

2 objc_class

objc_class繼承自objc_object(所以肯定有isa指針), 表示類對象, 底層仍然是結(jié)構(gòu)體, 其內(nèi)部的isa指針, 指向了該類的元類對象. 同時(shí), 內(nèi)部的superclass指向了自身的父類對象, NSObject對象superclass指向了nil, cache是一個(gè)方法緩存結(jié)構(gòu)體, bits是存儲變量、屬性,、方法等的結(jié)構(gòu)體

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    
    class_rw_t *data() { 
        return bits.data();
    }
    ...
	// 類相關(guān)的數(shù)據(jù)操作都是在此結(jié)構(gòu)體中, 不再全部貼出
}

2.1 cache_t

緩存方法, 消息傳遞時(shí), 會先通過哈希查找算法, 在此數(shù)據(jù)結(jié)構(gòu)中查詢是否有要執(zhí)行的方法緩存, 如果有則快速執(zhí)行該方法函數(shù), 這樣提高了消息傳遞的效率;

方法緩存策略, 是局部性原理的最佳應(yīng)用;

本質(zhì)是一個(gè)可增量的哈希表, 其內(nèi)部維護(hù)了一個(gè)由bucket_t組成的結(jié)構(gòu)體列表

struct cache_t {
    struct bucket_t *_buckets;
    mask_t _mask;
    mask_t _occupied;
public:
    struct bucket_t *buckets();
    ...
};

bucket_t內(nèi)部存儲了方法緩存key和無類型函數(shù)指針地址的映射關(guān)系, 在查找緩存時(shí), 通知指定的key查找到具體的bucket_t, 再從bucket_t中查詢到函數(shù)IMP地址, 進(jìn)而去執(zhí)行函數(shù)

struct bucket_t {
private:
    cache_key_t _key;
    IMP _imp;

public:
    inline cache_key_t key() const { return _key; }
    inline IMP imp() const { return (IMP)_imp; }
    inline void setKey(cache_key_t newKey) { _key = newKey; }
    inline void setImp(IMP newImp) { _imp = newImp; }

    void set(cache_key_t newKey, IMP newImp);
};

cache內(nèi)存結(jié)構(gòu)示意圖

2.2 class_data_bits_t

  • class_data_bits_t結(jié)構(gòu)主要是對class_rw_r的封裝
  • class_rw_r又是對class_ro_r的封裝
struct class_rw_t {
	// class_rw_t部分代碼
    uint32_t flags;
    uint32_t version;
	// 指向只讀的結(jié)構(gòu)體, 存儲類初始內(nèi)容
    const class_ro_t *ro;
	/*
	三個(gè)可讀寫二維數(shù)組, 存儲了類的初始化信息, 內(nèi)容
	*/
    method_array_t methods;			// 方法列表
    property_array_t properties;	// 屬性列表
    protocol_array_t protocols;		// 協(xié)議列表
	// 第一個(gè)子類
    Class firstSubclass;
    // 下一個(gè)同級類
    Class nextSiblingClass;
};

class_ro_t結(jié)構(gòu)

struct class_ro_t {
   	// class_ro_t部分代碼
    const char * name;
    // class_ro_t存儲的是類在編譯期就確定的方法, 屬性, 協(xié)議等
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};

需要注意的是, class_ro_t存儲的是類在編譯期就確定的內(nèi)容信息, 而class_rw_t不僅包含了類在編譯期的內(nèi)容信息(其實(shí)是把class_ro_t的內(nèi)容合并), 還包含了在運(yùn)行時(shí)動態(tài)添加的類內(nèi)容, 如分類添加的方法, 屬性, 協(xié)議等內(nèi)容; 一張圖來表示上述結(jié)構(gòu)之間的關(guān)系:
class_rw_t和class_ro_t

3 isa

在arm64為架構(gòu)之前, isa指針存儲了類或元類對象的地址信息, 從arm64架構(gòu)開始對isa指針(非指針型指針)進(jìn)行了優(yōu)化, 用位域存儲了除類或元類地址信息以外的其他信息, 如has_assoc表示是否設(shè)置關(guān)聯(lián)對象

union isa_t  {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
    struct {
    	// 標(biāo)記位, 0 代表指針型isa, 1代表非指針型isa
        uintptr_t indexed           : 1;
        // 是否有關(guān)聯(lián)對象
        uintptr_t has_assoc         : 1;
        // 是否有C  析構(gòu)函數(shù)
        uintptr_t has_cxx_dtor      : 1;
        // 存儲當(dāng)前對象的類或元類的內(nèi)存地址
        uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
        // 判斷對象是否已經(jīng)初始化
        uintptr_t magic             : 6;
        // 對象是否有弱引用指針
        uintptr_t weakly_referenced : 1;
        // 當(dāng)前對象是否有dealloc操作
        uintptr_t deallocating      : 1;
        // 當(dāng)前isa指針是否有外掛引用表
        // 引用計(jì)數(shù)值大于isa所能存儲最大值時(shí)
        // 就會綁定一個(gè)sidetable散列表屬性, 來存儲更多的引用計(jì)數(shù)信息
        uintptr_t has_sidetable_rc  : 1;
        // 額外的引用計(jì)數(shù)值
        uintptr_t extra_rc          : 19;
    };
}

這里需要注意

  • isa所屬對象是實(shí)例對象, 則其指向?qū)嵗龑ο蟮念悓ο?/li>
  • isa所屬對象是類對象, 則其指向類對象的元類對象
    在這里插入圖片描述

4 method_t

method_t是函數(shù)的底層數(shù)據(jù)結(jié)構(gòu), 是對函數(shù)的封裝, Apple對函數(shù)的介紹在這里

struct method_t {
    SEL name;			// 函數(shù)名稱
    const char *types;	// 函數(shù)返回值和參數(shù)
    IMP imp;			// 無類型函數(shù)指針指向函數(shù)體
    struct SortBySELAddress :
        public std::binary_function<const method_t&,
                                    const method_t&, bool> {
        bool operator() (const method_t& lhs,
                         const method_t& rhs)
        { return lhs.name < rhs.name; }
    };
};

4.1 函數(shù)的四要素

  • 名稱
  • 返回值
  • 參數(shù)
  • 函數(shù)體

4.2 types

Apple使用了Type Encodings技術(shù), 來實(shí)現(xiàn)類型編碼, Objective-C 運(yùn)行時(shí)庫內(nèi)部利用類型編碼幫助加快消息分發(fā).
結(jié)構(gòu)是個(gè)列表, 包含了函數(shù)的返回值, 參數(shù)1, 參數(shù)2, 參數(shù)3 …, 其中函數(shù)的返回值存儲在第0個(gè)位置, 因?yàn)楹瘮?shù)只有一個(gè)返回值(Go支持多返回值), 而參數(shù)可以有多個(gè).

對于一個(gè)無類型無參數(shù)的函數(shù), 其types值為 “V@:”

- (void)method {
    // 其中
    // V對應(yīng)返回值, 代表返回值類型為void
    // @對應(yīng)第一個(gè)參數(shù), id類型代表一個(gè)對象, 默認(rèn)第一個(gè)參數(shù)是對象本身(self), 且該參數(shù)是固定的
    // :對應(yīng)SEL, 代表該參數(shù)是個(gè)方法選擇器, 且該參數(shù)是默認(rèn)的第二個(gè)固定參數(shù)
}

5 一張圖表明各數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系

runtime基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

二 實(shí)例對象,、類對象和元類對象

一大佬(膜拜)畫的一張圖, 足以說明三者之間的關(guān)系.( Apple官網(wǎng)也有類似的描述,但是個(gè)人感覺沒有下面這張圖更精彩)
實(shí)例、類與元類

  • 實(shí)例對象的isa指針指向其類對象
  • 類對象的isa指針指向其元類對象
  • 任何元類對象的isa指針都指向根元類對象
  • 類對象的superclass指針指向其父類對象, 根類對象指向nil
  • 元類對象的superclass指針指向其父元類對象, 根元類對象指向根類

其中, 根類在Objective-C中即為NSObject. 實(shí)例對象其實(shí)就是objc_object(), 類對象就是objc_class(); 上面講到, objc_class()是繼承自objc_object(), 因此類對象中也有isa指針

typedef struct objc_object {
    Class isa;
} *id;

從底層數(shù)據(jù)結(jié)構(gòu)可以看出, 類對象中存儲了實(shí)例對象方法列表, 成員變量等內(nèi)容; 同時(shí), 元類對象中存儲了類對象的類方法列表等內(nèi)容;

1 實(shí)例方法調(diào)用時(shí)是如何查找的

當(dāng)一個(gè)實(shí)例對象調(diào)用一個(gè)實(shí)例方法時(shí)

  • 首先會根據(jù)該對象的isa指針, 查到到其類對象, 在類對象方法列表中查詢是否有所調(diào)用方法的實(shí)現(xiàn);
  • 如果沒有, 則類對象會根據(jù)自身的superclass指針查找其父類對象, 在父類對象方法列表中查詢是否有所調(diào)用方法的同名方法實(shí)現(xiàn);
  • 遞歸調(diào)用直至根類對象, 如果中間有任何一步查詢到了具體的方法實(shí)現(xiàn), 就去執(zhí)行具體的函數(shù)調(diào)用;
  • 如果直至根類, 仍然沒有找到方法實(shí)現(xiàn), 則會調(diào)用系統(tǒng)兩個(gè)方法, 然后走系統(tǒng)調(diào)用流程;
  (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
  (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

具體的消息傳遞流程請往下看

2 self和super

self是當(dāng)前類的因此參數(shù), 指向類的實(shí)例對象, 進(jìn)行方法調(diào)用時(shí), 代表從當(dāng)前類開始進(jìn)行查找

OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

super本質(zhì)是個(gè)編譯器標(biāo)識符, 僅代表方法查找時(shí)從當(dāng)前對象所屬父類開始查找方法實(shí)現(xiàn)

OBJC_EXPORT id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

三 消息傳遞與消息轉(zhuǎn)發(fā)

在開發(fā)中, 我們經(jīng)常會碰見這樣子一個(gè)錯(cuò)誤 unrecognized selector sent to instance xx
大致意思是, 你調(diào)用了一個(gè)并不存在的方法. 現(xiàn)在, 我們會深入的探究一下為什么會出現(xiàn)這個(gè)異常.
其實(shí)上面這個(gè)異常會正好就是我們要講的, 在Objective-C的消息機(jī)制中, 用OC消息機(jī)制來說: 如果消息在傳遞的過程中找不到具體的IMP, 內(nèi)部就觸發(fā)了消息轉(zhuǎn)發(fā)機(jī)制, 而系統(tǒng)的消息轉(zhuǎn)發(fā)機(jī)制默認(rèn)實(shí)現(xiàn)是拋出上述的異常. 接下來, 我們分別講述消息的傳遞和轉(zhuǎn)發(fā).

我們知道Objective-C是動態(tài)語言, 方法的調(diào)用并不像C的靜態(tài)綁定一樣, 在編譯的時(shí)候就確定了程序運(yùn)行時(shí)該調(diào)用哪個(gè)函數(shù)(C中沒有方法實(shí)現(xiàn)會報(bào)錯(cuò)), 而是在運(yùn)行時(shí)基于runtime這個(gè)動態(tài)運(yùn)行時(shí)庫通過一系列的查找才決定調(diào)用哪個(gè)函數(shù), 這樣的調(diào)用方式更加靈活, 我們甚至可以在運(yùn)行時(shí)動態(tài)的修改某個(gè)方法的實(shí)現(xiàn), 與當(dāng)下流行的"熱更新"技術(shù)有些類似. 而這個(gè)查找過程就是Objective-C的消息機(jī)制.

1 消息傳遞流程

在Objective-C中, 方法調(diào)用其實(shí)就是給某個(gè)對象發(fā)送消息, 在編譯后的文件中我們發(fā)現(xiàn), 底層都轉(zhuǎn)變?yōu)楹瘮?shù)調(diào)用

// 返回值, 參數(shù)1: 固定self, 參數(shù)2: 固定SEL, 后面是參數(shù)3, 參數(shù)4....
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

從代碼中可以看到, 消息發(fā)送函數(shù)有兩個(gè)默認(rèn)的參數(shù), 第一個(gè)是消息接受者receiver, 默認(rèn)就是當(dāng)前對象self; 第二個(gè)默認(rèn)參數(shù)是SEL, SEL的本質(zhì)的方法選擇器selector; (閱讀運(yùn)行時(shí)的文檔你會發(fā)現(xiàn), 幾乎所有方法調(diào)用都和selector有關(guān)系)! 所以, 我們的方法調(diào)用可以這樣表示** [receiver selector] **, 那么這個(gè)selector究竟是何方神圣, 遺憾的是我在Apple和GNU提供的runtime代碼中,都只找到了這一行代碼.

typedef struct objc_selector *SEL;

不過Apple給了說明, 方法選擇器selector就是個(gè)映射到C中的字符串. 根據(jù)我翻閱的各種資料都顯示, selector就是個(gè)C字符串類型的方法名稱.

Method selectors are used to represent the name of a method at runtime. A method selector is a C string that has been registered (or “mapped“) with the Objective-C runtime. Selectors generated by the compiler are automatically mapped by the runtime when the class is loaded.

說了半天, 跟我們的運(yùn)行時(shí)有什么關(guān)系(objc_msgSend()是[receiver selector]編譯階段實(shí)現(xiàn)的)?那么, objc_msgSend()函數(shù)在運(yùn)行時(shí)是如何進(jìn)一步調(diào)用的呢?

  • 首先, 通過 recevier的isa指針尋找到recevier的class(類);
  • 其次, 先在class中的cache list(緩存列表)查找是否有對應(yīng)的緩存selector;
  • 如果在緩存列表中查找到, 那么就根據(jù)selector(key)直接執(zhí)行方法對應(yīng)的IMP(value);
  • 否則, 繼續(xù)在 class的method list(方法列表)中查找對應(yīng)的 selector;
  • 如果沒有找到對應(yīng)的selector, 就繼續(xù)在它的 superclass(父類)中尋找;
  • 最后, 如果找到對應(yīng)的 selector, 直接執(zhí)行 recever 對應(yīng) selector 方法實(shí)現(xiàn)的 IMP(方法實(shí)現(xiàn))
  • 否則, 系統(tǒng)進(jìn)入默認(rèn)消息轉(zhuǎn)發(fā)機(jī)制.

我們用一張圖來表示上述流程消息傳遞流程
有時(shí)候, 我們會通過super調(diào)用, 其實(shí)道理是一樣的, 編譯后會生成objc_msgSendSuper()函數(shù)

OBJC_EXPORT id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

而objc_super結(jié)構(gòu)體內(nèi)部, 消息接受者仍然是receiver當(dāng)前實(shí)例對象, 與上面不唯一不同的是, self是從當(dāng)前對象的類對象中開始查找對應(yīng)實(shí)現(xiàn), 而super則是跨過當(dāng)前對象的類對象直接從類對象的父類對象開始查找方法實(shí)現(xiàn);

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained id receiver;
};

2 消息轉(zhuǎn)發(fā)流程

在消息的傳遞過程中, 我們講到, 如果receiver 找不到對應(yīng)的selector的IMP實(shí)現(xiàn), 則會進(jìn)入系統(tǒng)的默認(rèn)消息轉(zhuǎn)發(fā)流程. 而系統(tǒng)默認(rèn)處理消息轉(zhuǎn)發(fā)的機(jī)制就會拋出unrecognized selector sent to instance xx異常, 然后結(jié)束整個(gè)消息轉(zhuǎn)發(fā). 如果想要避免這種情況的發(fā)生, 我們就需要在如果selector找不到的情況下在運(yùn)行時(shí)動態(tài)的給receiver添加實(shí)現(xiàn).
幸運(yùn)的是雖然系統(tǒng)默認(rèn)默認(rèn)流程是拋異常, 但是在拋異常的方法調(diào)用過程中, 系統(tǒng)給我們開了口子, 讓我們可以通過 動態(tài)解析,、receiver重定向,、消息重定向等對消息進(jìn)行處理, 流程如下圖:
消息轉(zhuǎn)發(fā)流程

2.1 消息動態(tài)解析

在系統(tǒng)處理消息轉(zhuǎn)發(fā)的過程中, 首先會根據(jù)調(diào)用對象類型不同分別調(diào)用如下兩個(gè)api, 我們可以通過重載在這兩個(gè)方法內(nèi)部動態(tài)添加方法, 進(jìn)而避免crash

// 找不到類方法, 重載此類方法添加類方法實(shí)現(xiàn)
  (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
// 找不到實(shí)例方法, 重載此類方法添加實(shí)例方法實(shí)現(xiàn)
  (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

我們以實(shí)例方法為例舉個(gè)??

// 此處實(shí)例方法test沒有方法實(shí)現(xiàn)
  (BOOL)resolveInstanceMethod:(SEL)sel {
    // 判斷是否是test方法
    if (sel == @selector(test)) {
        NSLog(@"resolveInstanceMethod:");
        // 動態(tài)添加test方法的實(shí)現(xiàn)
        class_addMethod(self, @selector(test), testImp, "v@:");
    }
    
    return [super resolveInstanceMethod:sel];
}
void testImp (void) {
    NSLog(@"test invoke");
}

2.2 消息接受者重定向

如果在resolveInstanceMethod:SEL中沒有處理消息(即返回NO), 則系統(tǒng)會給我們第二次機(jī)會, 調(diào)用forwardingTargetForSelector:SEL! 方法返回值是個(gè)id類型, 告訴系統(tǒng)這個(gè)實(shí)例方法調(diào)用轉(zhuǎn)由哪個(gè)對象(如果是類方法調(diào)用則返回類對象; 如果是實(shí)例方法調(diào)用, 則返回實(shí)例對象)來接受處理, 如果我們指定了新的receiver, 就把消息重新交給新的receiver處理.
同樣的, 我們舉個(gè)??

 - (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        NSLog(@"forwardingTargetForSelector:");
        // 重定向, 讓ForwardObj對象作為receiver, 接收處理這個(gè)消息
        return [[ForwardObj alloc] init];
    }
    
    return [super forwardingTargetForSelector:aSelector];
}

2.3 消息重定向

如果系統(tǒng)給我們第二次機(jī)會時(shí), 我們返回的對象是nil, 或者self, 那系統(tǒng)會最后一次給我們避免crash的機(jī)會, 即消息重定向流程, 調(diào)用methodSignatureForSelector方法, 返回值是個(gè)方法簽名
繼續(xù)舉個(gè)??

// 定義函數(shù)參數(shù)和返回值類型, 并返回函數(shù)簽名
 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        NSLog(@"methodSignatureForSelector:");
        // v代表方法簽名的返回值void, @ id類型代表self
        // : SEL類型, 代表方法選擇器, 其實(shí)就是@selector(test)
        return [NSMethodSignature signatureWithObjCTypes:"@:"];
    }
    
    return [super methodSignatureForSelector:aSelector];
}
// 消息重定向
 - (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation:");
    ForwardObj *obj = [[ForwardObj alloc] init];
    if ([obj performSelector:anInvocation.selector]) {
    	// 如果obj對象可以響應(yīng), 則消息轉(zhuǎn)發(fā)給obj對象處理
        [anInvocation invokeWithTarget: obj];
    } else {
    	// 否則, 拋異常找不到方法對應(yīng)的實(shí)現(xiàn)
        [self doesNotRecognizeSelector:anInvocation.selector];
    }
}

四 動態(tài)方法

1 動態(tài)添加方法

我們在消息轉(zhuǎn)發(fā)的過程中已經(jīng)用到了動態(tài)添加方法

// 動態(tài)添加底層實(shí)現(xiàn)
// cls: 為哪個(gè)動態(tài)添加方法
// name: 要添加的方法名稱(方法選擇器selector)
// IMP: 無類型函數(shù)指針地址
// types: Type Encodings 函數(shù)參數(shù)和返回值
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) {
    if (!cls) return NO;

    rwlock_writer_t lock(runtimeLock);
    return ! addMethod(cls, name, imp, types ?: "", NO);
}

2 動態(tài)方法解析

同樣的, 在消息轉(zhuǎn)發(fā)過程中, 其實(shí)就是對方法的動態(tài)解析. 現(xiàn)在我們要講述另一個(gè)方法動態(tài)解析的類型, @dynamic
dynamic: 這個(gè)詞中文意思是動態(tài). 什么動態(tài)? 動態(tài)運(yùn)行時(shí)的動態(tài), 動態(tài)方法的動態(tài), 動態(tài)解析的動態(tài), 動態(tài)語言的動態(tài)!
被@dynamic標(biāo)記的屬性, 在編譯時(shí)并沒有對其getter和setter方法做實(shí)現(xiàn), 而是

  • 動態(tài)運(yùn)行時(shí), 把其實(shí)現(xiàn)推遲到了運(yùn)行時(shí), 即將函數(shù)決議推遲到運(yùn)行時(shí)
  • 而靜態(tài)語言, 是在編譯期就進(jìn)行了函數(shù)決議

轉(zhuǎn)載請注明作者和鏈接哦!
參考資料:
GNU
NS類型編碼
運(yùn)行時(shí)編程指南
Objective-C 運(yùn)行時(shí)
Objective-C 編程
iOS 開發(fā):『Runtime』詳解(一)基礎(chǔ)知識

來源:https://www./content-4-650651.html

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多