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

分享

【OC刨根問(wèn)底】

 nisz 2016-06-25
原文出處: 楚天舒   

從C的面向過(guò)程到接觸OC的對(duì)象,、消息的過(guò)渡初期總會(huì)有知其然不知其所以然的糾結(jié),相關(guān)的學(xué)習(xí)資源一般都是介紹有什么,、使用步驟一二三四的套路,這樣就很難知道知道本質(zhì)是什么,能干什么不能干什么,為什么要選擇用它,。而實(shí)際開發(fā)過(guò)程,都是先有什么要解決,,再努力找到實(shí)現(xiàn)方法,。人腦的容易接受的信息,也多是主干到分枝的思維導(dǎo)圖,,綱舉目張,。所以,試著以自己的粗淺理解來(lái)寫一點(diǎn)關(guān)于OC運(yùn)行時(shí)的東西,。

代碼的思想,,大概是把重復(fù)且不變的東西封裝成可以重復(fù)利用的共性,,把變化的東西細(xì)化為具體獨(dú)立松耦合的變量。這些可以是數(shù)據(jù)類型,,也可以是實(shí)現(xiàn)的方法代碼片段,。類也是封裝的產(chǎn)物和可封裝的對(duì)象。被封裝的東西,,需要找到里面內(nèi)容來(lái)具體地實(shí)現(xiàn),,就需要給里面內(nèi)容加個(gè)關(guān)聯(lián)的映射標(biāo)識(shí),比如索引(數(shù)組),、字符串(字典),、指針,、SEL(方法的代號(hào)),、isa(對(duì)象)等等。大概來(lái)說(shuō)就是用類和對(duì)象來(lái)封裝父類指針和方法列表,,用映射來(lái)找到實(shí)現(xiàn)方法的代碼片段,。


主要思路:

實(shí)例對(duì)象instance->類class->方法method(->SEL->IMP)->實(shí)現(xiàn)函數(shù)

實(shí)例對(duì)象只存放isa指針和實(shí)例變量,由isa指針找到所屬類,,類維護(hù)一個(gè)運(yùn)行時(shí)可接收的方法列表,;方法列表中的每個(gè)入口是一個(gè)方法(Method),其中key是一個(gè)特定名稱,,即選擇器(SEL),,其對(duì)應(yīng)一個(gè)指向底層C實(shí)現(xiàn)函數(shù)的指針,即實(shí)現(xiàn)(IMP),,,。運(yùn)行時(shí)機(jī)制最關(guān)鍵核心是objc_msgSend函數(shù),通過(guò)給target(類)發(fā)送selecter(SEL)來(lái)傳遞消息,,找到匹配的IMP,,指向?qū)崿F(xiàn)的C函數(shù)。

由于OC的運(yùn)行時(shí)動(dòng)態(tài)特性,,在編譯之后可以在運(yùn)行時(shí)通過(guò)C操作函數(shù),,動(dòng)態(tài)地創(chuàng)建修改類信息,動(dòng)態(tài)綁定方法和重寫實(shí)現(xiàn),,靈活地實(shí)現(xiàn)一些自定義功能,。

紙上寫了個(gè)大綱,沒(méi)有畫思維導(dǎo)圖,,簡(jiǎn)單列個(gè)目錄:

一,、運(yùn)行時(shí)Runtime介紹

二、類的本質(zhì):

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
   - 類相關(guān):
           + 數(shù)據(jù)類型:class,,object,;
                    - isa 元類
                    - superClass 根類
           + 操作函數(shù):
                     - class_
                               + get: 類名,,父類; 實(shí)例變量,成員變量,;屬性,;實(shí)例方法,類方法,,方法實(shí)現(xiàn),;
                               + copy: 成員變量列表;屬性列表,;方法列表,;協(xié)議列表;
                               + add: 成員變量,;屬性,;方法,;協(xié)議;
                               + replace:屬性;方法,;
                               + respond:響應(yīng)方法判斷(內(nèi)?。?/div>
                               + isMetaclass:元類判斷(內(nèi)?。?/div>
                               + conform:遵循協(xié)議判斷(內(nèi)?。?/div>
                     - objc_
                               + get: 實(shí)例變量;成員變量,;類名,;類;元類,;關(guān)聯(lián)對(duì)象,;
                               + copy: 對(duì)象;類,;類列表,;協(xié)議列表;
                               + set: 實(shí)例變量,;成員變量,;類;類列表,;協(xié)議,;關(guān)聯(lián)對(duì)象;
                               + dispose: 對(duì)象,;
                     - 動(dòng)態(tài)創(chuàng)建/銷毀類,、對(duì)象
   - 成員變量、屬性相關(guān):
           + 數(shù)據(jù)類型:Ivar,;objc_property_t,;objc_property_attribute_t,;
           + 操作函數(shù):
                      - ivar_
                      - property_
   - 方法消息相關(guān):
           + 數(shù)據(jù)類型:SELIMP; Method,;方法緩存
           + 操作函數(shù):
                      - method_
                               + invoke: 方法實(shí)現(xiàn)的返回值,;
                               + get: 方法名;方法實(shí)現(xiàn),;參數(shù)與返回值相關(guān),;
                               + set:方法實(shí)現(xiàn);
                               + exchange:交換方法實(shí)現(xiàn)
           + 方法調(diào)用:msgSend函數(shù)(找到方法實(shí)現(xiàn))
           + 消息轉(zhuǎn)發(fā):
                     - Method Resolution
                     - Fast Forwarding
                     - Normal Forwarding
   - 協(xié)議相關(guān):
           + 數(shù)據(jù)類型:Protocol,;
           + 操作函數(shù):
                      - protocol_
                               + get: 協(xié)議,;屬性;
                               + copy:協(xié)議列表,;屬性列表,;
                               + add:屬性;方法,;協(xié)議,;
                               + isEqual:判斷兩協(xié)議等同,;
                               + comform:判斷是否遵循協(xié)議,;
   - 其他:類名;版本號(hào),;類信息,;(忽略)

三、 動(dòng)態(tài)實(shí)現(xiàn):

  • Method Swizzling;
  • ISA Swizzling,;

四,、 其他概念:category;super,;等等,。想起來(lái)再加…


————進(jìn)入正題———–

一、運(yùn)行時(shí)Runtime介紹

作用:在程序運(yùn)行的時(shí)候執(zhí)行編譯后的代碼,,可以:

Objective-C
1
2
      > 動(dòng)態(tài)(創(chuàng)建),、(修改)(內(nèi)省)  ```方法`
      > 消息傳遞

運(yùn)行時(shí)Runtime的一切都圍繞這兩個(gè)中心:類的動(dòng)態(tài)配置 和 消息傳遞,。通過(guò)操作函數(shù)來(lái)配置類信息,,通過(guò)msgSend函數(shù)傳遞消息。
本質(zhì):libobjc.dylib,,C和匯編(消息傳遞機(jī)制由匯編寫成)寫成,。

二、類的本質(zhì):

1,、類相關(guān):

數(shù)據(jù)結(jié)構(gòu)(本源):Class類型的結(jié)構(gòu)體,。在objc/runtime.h中查看其成員:

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父類
    const char *name                        OBJC2_UNAVAILABLE;  // 類名
    long version                            OBJC2_UNAVAILABLE;  // 類的版本信息,,默認(rèn)為0
    long info                               OBJC2_UNAVAILABLE;  // 類信息,供運(yùn)行期使用的一些位標(biāo)識(shí)
    long instance_size                      OBJC2_UNAVAILABLE;  // 類的實(shí)例變量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 類的成員變量鏈表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定義的鏈表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法緩存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;

a,、數(shù)據(jù)類型:
isa和super_class :不同的類中可以有相同的方法(同一個(gè)類的方法不能同名,,哪怕參數(shù)類型不同,后面解釋…),,所以要先確定是那個(gè)類,。isa和super_class是找到實(shí)現(xiàn)函數(shù)的關(guān)鍵映射,決定找到存放在哪個(gè)類的方法實(shí)現(xiàn),。(isa用于自省確定所屬類,,super_class確定繼承關(guān)系)。

實(shí)例對(duì)象的isa指針指向類,,類的isa指針指向其元類(metaClass),。對(duì)象就是一個(gè)含isa指針的結(jié)構(gòu)體。類存儲(chǔ)實(shí)例對(duì)象的方法列表,,元類存儲(chǔ)類的方法列表,,元類也是類對(duì)象。
這是id類型的結(jié)構(gòu)(類似于C里面的void *):

Objective-C
1
2
3
4
5
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;

當(dāng)創(chuàng)建實(shí)例對(duì)象時(shí),,分配的內(nèi)存包含一個(gè)objc_object數(shù)據(jù)結(jié)構(gòu),,然后是類到父類直到根類NSObject的實(shí)例變量的數(shù)據(jù)。NSObject類的alloc和allocWithZone:方法使用函數(shù)class_createInstance來(lái)創(chuàng)建objc_object數(shù)據(jù)結(jié)構(gòu),。

向一個(gè)Objective-C對(duì)象發(fā)送消息時(shí),,運(yùn)行時(shí)庫(kù)會(huì)根據(jù)實(shí)例對(duì)象的isa指針找到這個(gè)實(shí)例對(duì)象所屬的類。Runtime庫(kù)會(huì)在類的方法列表由super_class指針找到父類的方法列表直至根類NSObject中去尋找與消息對(duì)應(yīng)的selector指向的方法,。找到后即運(yùn)行這個(gè)方法,。

1

metaClass.png

Objective-C
1
2
3
上圖是關(guān)于isasuper_class指針的圖解:
1isa:實(shí)例對(duì)象->->元類->(不經(jīng)過(guò)父元類)直接到根元類(NSObject的元類),,根元類的isa指向自己,;
2 superclass:類->父類->...->根類NSObject,,元類->父元類->...->根元類->根類,NSObjectsuperclass指向nil,。

b、操作函數(shù):類對(duì)象以class_為前綴,,實(shí)例對(duì)象以object_為前綴

  • class_:
    get: 類名,,父類,元類,;實(shí)例變量,,成員變量;屬性,;實(shí)例方法,,類方法,,方法實(shí)現(xiàn);

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 獲取類的類名
const char * class_getName ( Class cls );
// 獲取類的父類
Class class_getSuperclass ( Class cls );
// 獲取實(shí)例大小
size_t class_getInstanceSize ( Class cls );
// 獲取類中指定名稱實(shí)例成員變量的信息
Ivar class_getInstanceVariable ( Class cls, const char *name );
// 獲取類成員變量的信息
Ivar class_getClassVariable ( Class cls, const char *name );
// 獲取指定的屬性
objc_property_t class_getProperty ( Class cls, const char *name );
// 獲取實(shí)例方法
Method class_getInstanceMethod ( Class cls, SEL name );
// 獲取類方法
Method class_getClassMethod ( Class cls, SEL name );
// 獲取方法的具體實(shí)現(xiàn)
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );

copy: 成員變量列表,;屬性列表,;方法列表;協(xié)議列表,;

Objective-C
1
2
3
4
5
6
7
8
// 獲取整個(gè)成員變量列表
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
// 獲取屬性列表
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
// 獲取所有方法的列表
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
// 獲取類實(shí)現(xiàn)的協(xié)議列表
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );

add: 成員變量,;屬性;方法,;協(xié)議,;(添加成員變量只能在運(yùn)行時(shí)創(chuàng)建的類,且不能為元類)

Objective-C
1
2
3
4
5
6
7
8
// 添加成員變量
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
// 添加屬性
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
// 添加協(xié)議
BOOL class_addProtocol ( Class cls, Protocol *protocol );

replace:屬性,;方法,;

Objective-C
1
2
3
4
// 替換類的屬性
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
// 替代方法的實(shí)現(xiàn)
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );

respond:響應(yīng)方法判斷(內(nèi)省)

Objective-C
1
2
// 類實(shí)例是否響應(yīng)指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );

isMetaClass:元類判斷(內(nèi)?。?/p>

Objective-C
1
2
// 判斷給定的Class是否是一個(gè)元類
BOOL class_isMetaClass ( Class cls );

conform:遵循協(xié)議判斷(內(nèi)?。?/p>

Objective-C
1
2
// 返回類是否實(shí)現(xiàn)指定的協(xié)議
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );

  • objc_:
    get: 實(shí)例變量;成員變量,;類名,;類;元類,;關(guān)聯(lián)對(duì)象

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
// 獲取對(duì)象實(shí)例變量
Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue );
// 獲取對(duì)象中實(shí)例變量的值
id object_getIvar ( id obj, Ivar ivar );
// 獲取對(duì)象的類名
const char * object_getClassName ( id obj );
// 獲取對(duì)象的類
Class object_getClass ( id obj );
Class objc_getClass ( const char *name );
// 返回指定類的元類
Class objc_getMetaClass ( const char *name );
//獲取關(guān)聯(lián)對(duì)象
id objc_getAssociatedObject(self, &myKey);

copy:對(duì)象,;類,;類列表,;協(xié)議列表;

Objective-C
1
2
3
4
// 獲取指定對(duì)象的一份拷貝
id object_copy ( id obj, size_t size );
// 創(chuàng)建并返回一個(gè)指向所有已注冊(cè)類的指針列表
Class * objc_copyClassList ( unsigned int *outCount );

set: 實(shí)例變量,;類,;類列表;協(xié)議,;關(guān)聯(lián)對(duì)象,;

Objective-C
1
2
3
4
5
6
// 設(shè)置類實(shí)例的實(shí)例變量的值
Ivar object_setInstanceVariable ( id obj, const char *name, void *value );
// 設(shè)置對(duì)象中實(shí)例變量的值
void object_setIvar ( id obj, Ivar ivar, id value );
//設(shè)置關(guān)聯(lián)對(duì)象
void objc_setAssociatedObject(self, &myKey, anObject, OBJC_ASSOCIATION_RETAIN);

dispose: 對(duì)象;

Objective-C
1
2
// 釋放指定對(duì)象占用的內(nèi)存
id object_dispose ( id obj );

  • 動(dòng)態(tài)創(chuàng)建/銷毀類,、對(duì)象
    動(dòng)態(tài)創(chuàng)建/銷毀類:

Objective-C
1
2
3
4
5
6
7
8
// 創(chuàng)建一個(gè)新類和元類
Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );
// 銷毀一個(gè)類及其相關(guān)聯(lián)的類
void objc_disposeClassPair ( Class cls );
// 在應(yīng)用中注冊(cè)由objc_allocateClassPair創(chuàng)建的類
void objc_registerClassPair ( Class cls );

動(dòng)態(tài)創(chuàng)建/銷毀對(duì)象:

Objective-C
1
2
3
4
5
6
7
8
// 創(chuàng)建類實(shí)例
id class_createInstance ( Class cls, size_t extraBytes );
// 在指定位置創(chuàng)建類實(shí)例
id objc_constructInstance ( Class cls, void *bytes );
// 銷毀類實(shí)例
void * objc_destructInstance ( id obj );


2,、實(shí)例變量、屬性相關(guān):
實(shí)例變量和屬性也是類對(duì)象的關(guān)鍵配置,。

屬性變量的意義就是方便讓其他對(duì)象訪問(wèn)實(shí)例變量,,另外可以拓展實(shí)例變量的作用范圍。當(dāng)然,,你可以設(shè)置只讀或者可寫等,,設(shè)置方法也可自定義,。

a、數(shù)據(jù)類型:
Ivar,;

Objective-C
1
2
3
4
5
6
7
8
9
10
typedef struct objc_ivar *Ivar;
struct objc_ivar {
    char *ivar_name                 OBJC2_UNAVAILABLE;  // 變量名
    char *ivar_type                 OBJC2_UNAVAILABLE;  // 變量類型
    int ivar_offset                 OBJC2_UNAVAILABLE;  // 基地址偏移字節(jié)
#ifdef __LP64__
    int space                       OBJC2_UNAVAILABLE;
#endif
}

objc_property_t(取名可能是因?yàn)楫?dāng)時(shí)Objective-C1.0還沒(méi)屬性),;

Objective-C
1
typedef struct objc_property *objc_property_t;

objc_property_attribute_t(屬性的特性有:返回值、是否為atomic,、getter/setter名字,、是否為dynamic、背后使用的ivar名字,、是否為弱引用等),;

Objective-C
1
2
3
4
typedef struct {
    const char *name;           // 特性名
    const char *value;          // 特性值
} objc_property_attribute_t;

b、操作函數(shù):

  • ivar_:
    get:

Objective-C
1
2
3
4
5
6
7
8
// 獲取成員變量名
const char * ivar_getName ( Ivar v );
// 獲取成員變量類型編碼
const char * ivar_getTypeEncoding ( Ivar v );
// 獲取成員變量的偏移量
ptrdiff_t ivar_getOffset ( Ivar v );

  • property_:

Objective-C
1
2
3
4
5
6
7
8
9
10
11
// 獲取屬性名
const char * property_getName ( objc_property_t property );
// 獲取屬性特性描述字符串
const char * property_getAttributes ( objc_property_t property );
// 獲取屬性中指定的特性
char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );
// 獲取屬性的特性列表
objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );


3,、 方法消息相關(guān):
消息傳遞機(jī)制是Runtime的核心,,也即消息分派器objc_msgSend。先要知道幾個(gè)概念,。

a,、 數(shù)據(jù)類型:
SEL
SEL又叫選擇器,,是表示一個(gè)方法的selector的指針,映射方法的名字,。Objective-C在編譯時(shí),會(huì)依據(jù)每一個(gè)方法的名字,、參數(shù)序列,,生成一個(gè)唯一的整型標(biāo)識(shí)(Int類型的地址),這個(gè)標(biāo)識(shí)就是SEL,。
SEL的作用是作為IMP的KEY,,存儲(chǔ)在NSSet中,便于hash快速查詢方法,。SEL不能相同,,對(duì)應(yīng)方法可以不同。所以在Objective-C同一個(gè)類(及類的繼承體系)中,,不能存在2個(gè)同名的方法,,就算參數(shù)類型不同。多個(gè)方法可以有同一個(gè)SEL,。
不同的類可以有相同的方法名,。不同類的實(shí)例對(duì)象執(zhí)行相同的selector時(shí),會(huì)在各自的方法列表中去根據(jù)selector去尋找自己對(duì)應(yīng)的IMP,。
相關(guān)概念:類型編碼(Type Encoding)
編譯器將每個(gè)方法的返回值和參數(shù)類型編碼為一個(gè)字符串,,并將其與方法的selector關(guān)聯(lián)在一起。可以使用@encode編譯器指令來(lái)獲取它,。

Objective-C
1
typedef struct objc_selector *SEL;

中沒(méi)有公開具體的objc_selector結(jié)構(gòu)體成員,。但通過(guò)log可知SEL本質(zhì)是一個(gè)字符串。

IMP;
IMP是指向?qū)崿F(xiàn)函數(shù)的指針,,通過(guò)SEL取得IMP后,,我們就獲得了最終要找的實(shí)現(xiàn)函數(shù)的入口。

Objective-C
1
typedefine id (*IMP)(id, SEL, ...)

Objective-C
1
Method,;

這個(gè)結(jié)構(gòu)體相當(dāng)于在SEL和IMP之間作了一個(gè)綁定,。這樣有了SEL,我們便可以找到對(duì)應(yīng)的IMP,,從而調(diào)用方法的實(shí)現(xiàn)代碼,。(在運(yùn)行時(shí)才將SEL和IMP綁定, 動(dòng)態(tài)配置方法)

Objective-C
1
2
3
4
5
6
7
typedef struct objc_method *Method;
struct objc_method {
    SEL method_name                 OBJC2_UNAVAILABLE;  // 方法名
    char *method_types                  OBJC2_UNAVAILABLE; // 參數(shù)類型
    IMP method_imp                      OBJC2_UNAVAILABLE;  // 方法實(shí)現(xiàn)
}

objc_method_list 就是用來(lái)存儲(chǔ)當(dāng)前類的方法鏈表,objc_method存儲(chǔ)了類的某個(gè)方法的信息,。

Objective-C
1
2
3
4
5
6
7
8
9
struct objc_method_list {
    struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;
    int method_count                                                 OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                              OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;
}

方法緩存,;
方法調(diào)用最先是在方法緩存里找的,方法調(diào)用是懶調(diào)用,,第一次調(diào)用時(shí)加載后加到緩存池里,。一個(gè)objc程序啟動(dòng)后,需要進(jìn)行類的初始化,、調(diào)用方法時(shí)的cache初始化,,再發(fā)送消息的時(shí)候就直接走緩存(引申:+load方法和+initialize方法。load方法是首次加載類時(shí)調(diào)用,,絕對(duì)只調(diào)用一次,;initialize方法是首次給類發(fā)消息時(shí)調(diào)用,通常只調(diào)用一次,,但如果它的子類初始化時(shí)未定義initialize方法,,則會(huì)再調(diào)用一次它的initialize方法)。

Objective-C
1
2
3
4
5
6
7
8
9
struct objc_cache {
    // 緩存bucket的總數(shù)
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    // 實(shí)際緩存bucket的總數(shù)
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    // 指向Method數(shù)據(jù)結(jié)構(gòu)指針的數(shù)組
    Method buckets[1]                                        OBJC2_UNAVAILABLE;
};

b,、 操作函數(shù):

  • method_:
    invoke: 方法實(shí)現(xiàn)的返回值,;

Objective-C
1
2
3
4
5
// 調(diào)用指定方法的實(shí)現(xiàn)
id method_invoke ( id receiver, Method m, ... );
// 調(diào)用返回一個(gè)數(shù)據(jù)結(jié)構(gòu)的方法的實(shí)現(xiàn)
void method_invoke_stret ( id receiver, Method m, ... );

get: 方法名;方法實(shí)現(xiàn),;參數(shù)與返回值相關(guān);

Objective-C
1
2
3
4
5
6
7
8
9
10
11
// 獲取方法名
SEL method_getName ( Method m );
// 返回方法的實(shí)現(xiàn)
IMP method_getImplementation ( Method m );
// 獲取描述方法參數(shù)和返回值類型的字符串
const char * method_getTypeEncoding ( Method m );
// 返回方法的參數(shù)的個(gè)數(shù)
unsigned int method_getNumberOfArguments ( Method m );
// 通過(guò)引用返回方法指定位置參數(shù)的類型字符串
void method_getArgumentType ( Method m, unsigned int index, char *dst, size_t dst_len );

copy: 返回值類型,,參數(shù)類型

Objective-C
1
2
3
4
5
6
7
8
// 獲取方法的返回值類型的字符串
char * method_copyReturnType ( Method m );
// 獲取方法的指定位置參數(shù)的類型字符串
char * method_copyArgumentType ( Method m, unsigned int index );
// 通過(guò)引用返回方法的返回值類型字符串
void method_getReturnType ( Method m, char *dst, size_t dst_len );

set:方法實(shí)現(xiàn),;

Objective-C
1
2
// 設(shè)置方法的實(shí)現(xiàn)
IMP method_setImplementation ( Method m, IMP imp );

exchange:交換方法實(shí)現(xiàn)

Objective-C
1
2
// 交換兩個(gè)方法的實(shí)現(xiàn)
void method_exchangeImplementations ( Method m1, Method m2 );

description : 方法描述

Objective-C
1
2
// 返回指定方法的方法描述結(jié)構(gòu)體
struct objc_method_description * method_getDescription ( Method m );

  • sel_

Objective-C
1
2
3
4
5
6
7
8
9
10
11
// 返回給定選擇器指定的方法的名稱
const char * sel_getName ( SEL sel );
// 在Objective-C Runtime系統(tǒng)中注冊(cè)一個(gè)方法,將方法名映射到一個(gè)選擇器,,并返回這個(gè)選擇器
SEL sel_registerName ( const char *str );
// 在Objective-C Runtime系統(tǒng)中注冊(cè)一個(gè)方法
SEL sel_getUid ( const char *str );
// 比較兩個(gè)選擇器
BOOL sel_isEqual ( SEL lhs, SEL rhs );

c,、方法調(diào)用流程:向?qū)ο蟀l(fā)送消息,實(shí)際上是調(diào)用objc_msgSend函數(shù),,obj_msgSend的實(shí)際動(dòng)作就是:找到這個(gè)函數(shù)指針,,然后調(diào)用它,。

Objective-C
1
id objc_msgSend(receiver self, selector _cmd, arg1, arg2, ...)

self和_cmd是隱藏參數(shù),在編譯期被插入實(shí)現(xiàn)代碼,。
self:指向消息的接受者target的對(duì)象類型,,作為一個(gè)占位參數(shù),消息傳遞成功后self將指向消息的receiver,。
_cmd: 指向方法實(shí)現(xiàn)的SEL類型,。

當(dāng)向一般對(duì)象發(fā)送消息時(shí),調(diào)用objc_msgSend,;當(dāng)向super發(fā)送消息時(shí),,調(diào)用的是objc_msgSendSuper; 如果返回值是一個(gè)結(jié)構(gòu)體,,則會(huì)調(diào)用objc_msgSend_stret或objc_msgSendSuper_stret,。

0.1-檢查target是否為nil。如果為nil,,直接cleanup,,然后return。(這就是我們可以向nil發(fā)送消息的原因,。) 如果方法返回值是一個(gè)對(duì)象,,那么發(fā)送給nil的消息將返回nil;如果方法返回值為指針類型,,其指針大小為小于或者等于sizeof(void*),,float,double,,long double 或者long long的整型標(biāo)量,,發(fā)送給nil的消息將返回0;如果方法返回值為結(jié)構(gòu)體,發(fā)送給nil的消息將返回0,。結(jié)構(gòu)體中各個(gè)字段的值將都是0,;如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義的,。 0.2-如果target非nil,,在target的Class中根據(jù)Selector去找IMP。(因?yàn)橥粋€(gè)方法可能在不同的類中有不同的實(shí)現(xiàn),,所以我們需要依賴于接收者的類來(lái)找到的確切的實(shí)現(xiàn)),。
1-首先它找到selector對(duì)應(yīng)的方法實(shí)現(xiàn): *1.1-在target類的方法緩存列表里檢查有沒(méi)有對(duì)應(yīng)的方法實(shí)現(xiàn),有的話,,直接調(diào)用,。 *1.2-比較請(qǐng)求的selector和類方法列表中的selector,對(duì)應(yīng)的話,直接調(diào)用,。 *1.3-比較請(qǐng)求的selector和父類方法列表,,父類的父類,直至根類,,如果有對(duì)應(yīng),,則直接調(diào)用。(方法重寫攔截父類方法的原理) 2-調(diào)用方法實(shí)現(xiàn),,并將接收者對(duì)象及方法的所有參數(shù)傳給它,。 3-最后,將實(shí)現(xiàn)函數(shù)的返回值作為自己的返回值,。

d,、動(dòng)態(tài)方法解析與消息轉(zhuǎn)發(fā):如果以上的類中沒(méi)有找到對(duì)應(yīng)的selector(一般保險(xiǎn)起見先用respondsToSelector:內(nèi)省判斷):,還可以利用消息轉(zhuǎn)發(fā)機(jī)制依次執(zhí)行以下流程:

  • Method Resolution(動(dòng)態(tài)方法解析):
    用所屬類的類方法+(BOOL)resolveInstanceMethod:(實(shí)例方法)或者+(BOOL)resolveClassMethod:(類方法),在此方法里添加class_addMethod函數(shù),。一般用于@dynamic動(dòng)態(tài)屬性,。(當(dāng)一個(gè)屬性聲明為@dynamic,就是向編譯器保證編譯時(shí)不用管/get實(shí)現(xiàn),,一定會(huì)在運(yùn)行時(shí)實(shí)現(xiàn)),。
  • Fast Forwarding (快速消息轉(zhuǎn)發(fā)):
    如果上一步無(wú)法響應(yīng)消息,調(diào)用- (id)forwardingTargetForSelector:(SEL)aSelector方法,,將消息接受者轉(zhuǎn)發(fā)到另一個(gè)對(duì)象target(不能為self,,否則死循環(huán))。
  • Normal Forwarding(普通消息轉(zhuǎn)發(fā)):
    如果上一步無(wú)法響應(yīng)消息:
    調(diào)用方法簽名- (NSMethodSignature )methodSignatureForSelector:(SEL)aSelector,,方法簽名目的將函數(shù)的參數(shù)類型和返回值封裝,;
    如果返回非nil,則創(chuàng)建一個(gè)NSInvocation對(duì)象利用方法簽名和selector封裝未被處理的消息,,作為參數(shù)傳遞給- (void)forwardInvocation:(NSInvocation
    )anInvocation,。
    這一步比較耗時(shí)。

如果以上步驟(消息傳遞和消息轉(zhuǎn)發(fā))還是不能響應(yīng)消息,,則調(diào)動(dòng)doesNotRecognizeSelector:方法,,拋出異常。

Objective-C
1
unrecognized selector sent to instance

(消息轉(zhuǎn)發(fā)可以利用轉(zhuǎn)移消息接受對(duì)象,,實(shí)現(xiàn)偽多重繼承的效果,。)


4、 協(xié)議相關(guān):@protocol聲明了可以被其他任何類實(shí)現(xiàn)的方法,,協(xié)議僅僅是定義一個(gè)接口,,而由其他的類去負(fù)責(zé)實(shí)現(xiàn)。

數(shù)據(jù)類型:Protocol,;

Objective-C
1
typedef struct objc_object Protocol;

protocol是一個(gè)對(duì)象結(jié)構(gòu)體。

操作函數(shù):

  • objc_:

Objective-C
1
2
3
4
5
6
7
8
9
10
11
// 返回指定的協(xié)議
Protocol * objc_getProtocol ( const char *name );
// 獲取運(yùn)行時(shí)所知道的所有協(xié)議的數(shù)組
Protocol ** objc_copyProtocolList ( unsigned int *outCount );
// 創(chuàng)建新的協(xié)議實(shí)例
Protocol * objc_allocateProtocol ( const char *name );
// 在運(yùn)行時(shí)中注冊(cè)新創(chuàng)建的協(xié)議
void objc_registerProtocol ( Protocol *proto );

  • protocol_:
    get: 協(xié)議;屬性,;

Objective-C
1
2
3
4
// 返回協(xié)議名
const char * protocol_getName ( Protocol *p );
// 獲取協(xié)議的指定屬性
objc_property_t protocol_getProperty ( Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty );

copy:協(xié)議列表,;屬性列表;

Objective-C
1
2
3
4
// 獲取協(xié)議中的屬性列表
objc_property_t * protocol_copyPropertyList ( Protocol *proto, unsigned int *outCount );
// 獲取協(xié)議采用的協(xié)議
Protocol ** protocol_copyProtocolList ( Protocol *proto, unsigned int *outCount );

add:屬性,;方法,;協(xié)議;

Objective-C
1
2
3
4
5
6
7
8
// 為協(xié)議添加方法
void protocol_addMethodDescription ( Protocol *proto, SEL name, const char *types, BOOL isRequiredMethod, BOOL isInstanceMethod );
// 添加一個(gè)已注冊(cè)的協(xié)議到協(xié)議中
void protocol_addProtocol ( Protocol *proto, Protocol *addition );
// 為協(xié)議添加屬性
void protocol_addProperty ( Protocol *proto, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount, BOOL isRequiredProperty, BOOL isInstanceProperty );

Objective-C
1
isEqual:判斷兩協(xié)議等同,;

Objective-C
1
2
// 測(cè)試兩個(gè)協(xié)議是否相等
BOOL protocol_isEqual ( Protocol *proto, Protocol *other );

comform:判斷是否遵循協(xié)議,;

Objective-C
1
2
// 查看協(xié)議是否采用了另一個(gè)協(xié)議
BOOL protocol_conformsToProtocol ( Protocol *proto, Protocol *other );


5、 其他:類名,;版本號(hào),;類信息;(忽略)


三,、 動(dòng)態(tài)實(shí)現(xiàn):

  • Method Swizzling;
    Method Swizzling可以在運(yùn)行時(shí)通過(guò)修改類的方法列表中selector對(duì)應(yīng)的函數(shù)或者設(shè)置交換方法實(shí)現(xiàn),,來(lái)動(dòng)態(tài)修改方法??梢灾貙懩硞€(gè)方法而不用繼承,,同時(shí)還可以調(diào)用原先的實(shí)現(xiàn)。通常應(yīng)用于在category中添加一個(gè)方法,。
    為保證改變方法引起沖突,,確保方法混用只能一次性:
    比如,在+load方法或者dispatch_once中執(zhí)行,。
  • ISA Swizzling,;
    ISA Swizzling可以動(dòng)態(tài)修改對(duì)象的isa指針,改變對(duì)象的類,,類似于創(chuàng)建子類實(shí)現(xiàn)相同的功能,。KVO即是同過(guò)ISA Swizzling實(shí)現(xiàn)的。

四,、 其他概念:category,;super;

  • category:

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef struct objc_category *Category;
struct objc_category {
    char *category_name                          OBJC2_UNAVAILABLE; // 分類名
    char *class_name                             OBJC2_UNAVAILABLE; // 分類所屬的類名
    struct objc_method_list *instance_methods    OBJC2_UNAVAILABLE; // 實(shí)例方法列表
    struct objc_method_list *class_methods       OBJC2_UNAVAILABLE; // 類方法列表
    struct objc_protocol_list *protocols         OBJC2_UNAVAILABLE; // 分類所實(shí)現(xiàn)的協(xié)議列表
}  
// objc-runtime-new.h中定義:
struct category_t {
    const char *name;                        // name 是指 class_name 而不是 category_name
    classref_t cls;                          // cls是要擴(kuò)展的類對(duì)象,,編譯期間是不會(huì)定義的,,而是在Runtime階段通過(guò)name對(duì)應(yīng)到對(duì)應(yīng)的類對(duì)象
    struct method_list_t *instanceMethods;      
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;    // instanceProperties表示Category里所有的properties,(這就是我們可以通過(guò)objc_setAssociatedObject和objc_getAssociatedObject增加實(shí)例變量的原因,,)不過(guò)這個(gè)和一般的實(shí)例變量是不一樣的
};

category就是定義方法的結(jié)構(gòu)體,,instance_methods列表是objc_class中方法列表的一個(gè)子集,class_methods列表是元類方法列表的一個(gè)子集,。由其結(jié)構(gòu)成員可知,,category為什么不能添加成員變量(可添加屬性,,只有set/get方法)。

給category添加方法后,,category_list會(huì)生成method list,。這個(gè)方法列表是倒序添加的,也就是說(shuō),,新生成的category的方法會(huì)先于舊的category的方法插入,。(category的方法會(huì)優(yōu)先于類方法執(zhí)行)。

  • super:

super并不是隱藏參數(shù),,它實(shí)際上只是一個(gè)”編譯器標(biāo)示符”,,它負(fù)責(zé)告訴編譯器,當(dāng)調(diào)用方法時(shí),,跳過(guò)當(dāng)前類去調(diào)用父類的方法,,而不是本類中的方法。self是類的一個(gè)隱藏參數(shù),,每個(gè)方法的實(shí)現(xiàn)的第一個(gè)參數(shù)即為self,。實(shí)際上給super發(fā)消息時(shí),super還是與self指向的是相同的消息接收者,。

Objective-C
1
2
3
4
struct objc_super {
   __unsafe_unretained id receiver;
   __unsafe_unretained Class super_class;
};

原理:使用super來(lái)接收消息時(shí),,編譯器會(huì)生成一個(gè)objc_super結(jié)構(gòu)體。發(fā)送消息時(shí),,不是調(diào)用objc_msgSend函數(shù),,而是調(diào)用objc_msgSendSuper函數(shù):

Objective-C
1
id objc_msgSendSuper ( struct objc_super *super, SEL op, ... );

該函數(shù)實(shí)際的操作是:從objc_super結(jié)構(gòu)體指向的superClass的方法列表開始查找selector,找到后以objc->receiver去調(diào)用這個(gè)selector,。

  • Runtime開源源碼對(duì)一些方法的實(shí)現(xiàn):

Objective-C
1
2
3
4
5
- (Class)class ;
- (Class)class {
    return object_getClass(self);
}

Objective-C
1
2
3
4
5
+ (Class)class;
+ (Class)class {
    return self;
}

Objective-C
1
2
3
4
5
6
7
8
9
10
- (BOOL)isKindOf:aClass;// (for循環(huán)遍歷父類,,每次判斷返回的結(jié)果可能不同)
- (BOOL)isKindOf:aClass
{
    Class cls;
    for (cls = isa; cls; cls = cls->superclass)
        if (cls == (Class)aClass)
            return YES;
    return NO;
}

Objective-C
1
2
3
4
5
6
- (BOOL)isMemberOf:aClass;
- (BOOL)isMemberOf:aClass
{
    return isa == (Class)aClass;
}

 

加入伯樂(lè)在線專欄作者。擴(kuò)大知名度,,還能得贊賞,!詳見《招募專欄作者
1 贊 2 收藏 評(píng)論

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多