IOS中Runtime學(xué)習(xí)筆記


一.什么是Runtime (運(yùn)行時(shí)機(jī)制)

  1. Objective-C語(yǔ)言是一門(mén)動(dòng)態(tài)語(yǔ)言,他將很多的靜態(tài)語(yǔ)言在編譯和鏈接時(shí)做的事情放到了運(yùn)行時(shí)來(lái)Handle. 這中語(yǔ)言的優(yōu)點(diǎn): 會(huì)讓我們寫(xiě)代碼時(shí)更具靈活性,在運(yùn)行的時(shí)候我們可以把消息轉(zhuǎn)發(fā)給我們想要的對(duì)象,或者隨意交換一個(gè)方法的實(shí)現(xiàn)等。
  2. 這種特性意味著Objective-C不僅需要一個(gè)編譯器,還需要一個(gè)運(yùn)行時(shí)系統(tǒng)來(lái)執(zhí)行編譯的代碼。對(duì)于Objective-C來(lái)說(shuō),這個(gè)運(yùn)行時(shí)系統(tǒng)就像一個(gè)操作系統(tǒng)一樣:它讓所有的工作可以正常的運(yùn)行。這個(gè)運(yùn)行時(shí)系統(tǒng)即Objc Runtime。Objc Runtime其實(shí)是一個(gè)Runtime庫(kù),它基本上是用C和匯編寫(xiě)的,這個(gè)庫(kù)使得C語(yǔ)言有了面向?qū)ο蟮哪芰Α?/li>
  3. 對(duì)于C語(yǔ)言,函數(shù)的調(diào)用在編譯的時(shí)候會(huì)決定調(diào)用哪個(gè)函數(shù)。對(duì)于OC的函數(shù),屬于動(dòng)態(tài)調(diào)用過(guò)程,在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù),只有在真正運(yùn)行的時(shí)候才會(huì)根據(jù)函數(shù)的名稱(chēng)找到對(duì)應(yīng)的函數(shù)來(lái)調(diào)用。
  4. 在編譯階段,OC可以調(diào)用任何函數(shù),即使這個(gè)函數(shù)并未實(shí)現(xiàn),只要聲明過(guò)就不會(huì)報(bào)錯(cuò)。而在編譯階段,C語(yǔ)言調(diào)用未實(shí)現(xiàn)的函數(shù)就會(huì)報(bào)錯(cuò)。

二. 了解Objective-C中的類(lèi)和對(duì)象:
1. 類(lèi)--> Class
首先我們看一下蘋(píng)果的API文檔, 我們通過(guò)工程中導(dǎo)入#import <objc/objc.h>的頭文件, 點(diǎn)擊去我們會(huì)看到OC中的具體類(lèi)是怎么定義的,如下面代碼:

/// An opaque type that represents an Objective-C class.
譯:一個(gè)不透明的類(lèi)型代表一個(gè)objective - c類(lèi)
 typedef struct objc_class *Class;

通過(guò)上面的部分我們可以看出Objective-C類(lèi)是由Class類(lèi)型來(lái)表示的,實(shí)際上是一個(gè)指向objc_class結(jié)構(gòu)體的一個(gè)指針. 到這里你肯定想知道objc_class的這個(gè)結(jié)構(gòu)體是咋定義的呢? 下面就讓我們看看具體它里面是什么東東?

// objc_class結(jié)構(gòu)體
 struct objc_class {
 Class isa  OBJC_ISA_AVAILABILITY;
 
 #if !__OBJC2__
 Class super_class                                        OBJC2_UNAVAILABLE;  父類(lèi)
 const char *name                                         OBJC2_UNAVAILABLE;  類(lèi)名
 long version                                             OBJC2_UNAVAILABLE;  類(lèi)的版本信息,默認(rèn)為0
 long info                                                OBJC2_UNAVAILABLE;  類(lèi)信息,供運(yùn)行期使用的一些位標(biāo)識(shí)
 long instance_size                                       OBJC2_UNAVAILABLE;  該類(lèi)的實(shí)例變量大小
 struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;  該類(lèi)的成員變量鏈表
 struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;  方法定義的鏈表
 struct objc_cache *cache                                 OBJC2_UNAVAILABLE;  方法緩存
 struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;  協(xié)議鏈表
 #endif
 
 } OBJC2_UNAVAILABLE;

結(jié)構(gòu)體的具體字段的解析:
isa: 需要注意的是在Objective-C中,所有的類(lèi)自身也是一個(gè)對(duì)象,這個(gè)對(duì)象的Class里面也有一個(gè)isa指針,它指向metaClass(元類(lèi)),metaclass 存儲(chǔ)類(lèi)的static類(lèi)成員變量與static類(lèi)成員方法(+開(kāi)頭的方法);實(shí)例對(duì)象中的 isa 指向類(lèi)結(jié)構(gòu)稱(chēng)作 class(普通的),class 結(jié)構(gòu)存儲(chǔ)類(lèi)的普通成員變量與普通成員方法(-開(kāi)頭的方法,這也就是說(shuō)通過(guò)類(lèi)對(duì)象訪問(wèn)靜態(tài)變量和函數(shù) 實(shí)例對(duì)象訪問(wèn)普通的變量和函數(shù)
super_class:指向該類(lèi)的父類(lèi),如果該類(lèi)已經(jīng)是最頂層的根類(lèi)(如NSObject或NSProxy),則super_class為NULL
cache:用于緩存最近使用的方法。一個(gè)接收者對(duì)象接收到一個(gè)消息時(shí),它會(huì)根據(jù)isa指針去查找能夠響應(yīng)這個(gè)消息的對(duì)象。在實(shí)際使用中,這個(gè)對(duì)象只有一部分方法是常用的,很多方法其實(shí)很少用或者根本用不上。這種情況下,如果每次消息來(lái)時(shí),我們都是methodLists中遍歷一遍,性能勢(shì)必很差。這時(shí),cache就派上用場(chǎng)了。在我們每次調(diào)用過(guò)一個(gè)方法后,這個(gè)方法就會(huì)被緩存到cache列表中,下次調(diào)用的時(shí)候runtime就會(huì)優(yōu)先去cache中查找,如果cache沒(méi)有,才去methodLists中查找方法。這樣,對(duì)于那些經(jīng)常用到的方法的調(diào)用,但提高了調(diào)用的效率
info:運(yùn)行期使用的標(biāo)志位,比如0x1(CLS_CLASS)表示該類(lèi)為普通class,0x2(CLS_META)表示該類(lèi)為 metaclass。
** instance_size:實(shí)例大小,即內(nèi)存所占空間。
** ivars:
指向成員變量列表的指針。
methodLists:根據(jù)標(biāo)志位的不同可能指向不同,比如可能指向?qū)嵗椒斜恚蛘咧赶蝾?lèi)方法列表。
cache:因?yàn)镺bjective-C的消息轉(zhuǎn)發(fā)需要查找dispatch table甚至可能需要遍歷繼承體系,所以緩存最近使用的方法。
protocols:類(lèi)需要遵守的協(xié)議。

2. 對(duì)象--> id:
typedef struct objc_object {
Class isa;
} *id;

可以發(fā)現(xiàn), id可以用來(lái)表示任意一個(gè)對(duì)象,它是一個(gè) objc_object 結(jié)構(gòu)類(lèi)型的指針,其第一個(gè)成員是一個(gè) objc_class 結(jié)構(gòu)類(lèi)型的指針

我們的根類(lèi)NSObject也同樣是只有一個(gè)Class成員:
@interface NSObject <NSObject> {
Class isa;
}

這個(gè)isa到底是什么呢?官方介紹是這樣的:
Every object is connected to the run-time system through its isa instance variable, inherited from the NSObject class. isa identifies the object's class; it points to a structure that's compiled from the class definition. Through isa, an object can find whatever information it needs at run timesuch as its place in the inheritance hierarchy, the size and structure of its instance variables, and the location of the method implementations it can perform in response to messages.
譯: 每個(gè)對(duì)象連接到運(yùn)行時(shí)系統(tǒng)通過(guò)isa實(shí)例變量,繼承了NSObject類(lèi)。isa標(biāo)識(shí)對(duì)象的類(lèi),它指向一個(gè)結(jié)構(gòu),編譯后的類(lèi)定義。通過(guò)isa,一個(gè)對(duì)象可以找到任何信息需要在運(yùn)行timesuch作為其在繼承層次結(jié)構(gòu),規(guī)模和結(jié)構(gòu)的實(shí)例變量和方法實(shí)現(xiàn)它可以執(zhí)行的位置響應(yīng)消息
可見(jiàn),一個(gè)對(duì)象(Object)的isa指向了這個(gè)對(duì)象的類(lèi)(Class),而這個(gè)對(duì)象的類(lèi)(Class)的isa指向了metaclass。這樣我們就可以找到靜態(tài)方法和變量了.

3. 類(lèi)創(chuàng)建的運(yùn)行時(shí)過(guò)程:

① 類(lèi)的實(shí)例對(duì)象的 isa 指向它的類(lèi);類(lèi)的 isa 指向該類(lèi)的 metaclass;
② 類(lèi)的 super_class 指向其父類(lèi),如果該類(lèi)為根類(lèi)則值為 NULL;
③ metaclass 的 isa 指向根 metaclass,如果該 metaclass 是根 metaclass 則指向自身;
④ metaclass 的 super_class 指向父 metaclass,如果該 metaclass 是metaclass 則指向該 metaclass 對(duì)應(yīng)的類(lèi);
⑤ Object-C 為每個(gè)類(lèi)的定義生成兩個(gè) objc_class ,一個(gè)普通的 class,另一個(gè)即 metaclass。我們可以在運(yùn)行期創(chuàng)建這兩個(gè) objc_class 數(shù)據(jù)結(jié)構(gòu),然后使用 objc_addClass將 class 注冊(cè)到運(yùn)行時(shí)系統(tǒng)中,以此實(shí)現(xiàn)動(dòng)態(tài)地創(chuàng)建一個(gè)新的類(lèi)。

三. 項(xiàng)目中具體使用Runtime庫(kù)里面的函數(shù)介紹:
1. 類(lèi)(Class)相關(guān)操作函數(shù):

① ClassName操作的函數(shù):

/** 
 * Returns the name of a class.
 * 
 * @param cls A class object.
 * 
 * @return The name of the class, or the empty string if \\\\e cls is \\\\c Nil.
獲取類(lèi)的類(lèi)名,對(duì)于class_getName函數(shù),如果傳入的cls為Nil,則返回一個(gè)字字符串。
 */
 const char *class_getName(Class cls) 

/** 
 * Returns the class name of a given object.
 * 
 * @param obj An Objective-C object.
 * 
 * @return The name of the class of which \\\\e obj is an instance.
返回一個(gè)給定對(duì)象的類(lèi)名
 */
 const char *object_getClassName(id obj)

② super_class(父類(lèi)) 與 meta_class(元類(lèi))主要操作函數(shù)

/** 
 * Returns the superclass of a class.
 * 
 * @param cls A class object.
 * 
 * @return The superclass of the class, or \\\\c Nil if
 *  \\\\e cls is a root class, or \\\\c Nil if \\\\e cls is \\\\c Nil.
 *
 * @note You should usually use \\\\c NSObject's \\\\c superclass method instead of this function.
獲取類(lèi)的父類(lèi),當(dāng)cls為Nil或者cls為根類(lèi)時(shí),返回Nil。不過(guò)通常我們可以使用NSObject類(lèi)的superclass方法來(lái)達(dá)到同樣的目的。
 */
 Class class_getSuperclass(Class cls) 


/** 
 * Returns a Boolean value that indicates whether a class object is a metaclass.
 * 
 * @param cls A class object.
 * 
 * @return \\\\c YES if \\\\e cls is a metaclass, \\\\c NO if \\\\e cls is a non-meta class, 
 *  \\\\c NO if \\\\e cls is \\\\c Nil.
  判斷給定的Class是否是一個(gè)元類(lèi),如果是cls是元類(lèi),則返回YES;如果否或者傳入的cls為Nil,則返回NO
 */
BOOL class_isMetaClass(Class cls) 

③ 實(shí)例變量大小

/** 
 * Returns the size of instances of a class.
 * 
 * @param cls A class object.
 * 
 * @return The size in bytes of instances of the class \\\\e cls, or \\\\c 0 if \\\\e cls is \\\\c Nil.
 */
OBJC_EXPORT size_t class_getInstanceSize(Class cls) 

④ Ivars(成員變量)

//  在objc_class中,Ivars存放著所有成員變量.屬性的信息,ivars是一個(gè)數(shù)組,數(shù)組中每個(gè)元素是指向Ivar(變量信息)的指針

/** 
 * Returns the \\\\c Ivar for a specified instance variable of a given class.
 * 
 * @param cls The class whose instance variable you wish to obtain.
 * @param name The name of the instance variable definition to obtain.
 * 
 * @return A pointer to an \\\\c Ivar data structure containing information about 
 *  the instance variable specified by \\\\e name.
獲取class中指定名稱(chēng)實(shí)例成員變量的信息
 */
 Ivar class_getInstanceVariable(Class cls, const char *name)


/** 
 * Returns the Ivar for a specified class variable of a given class.
 * 
 * @param cls The class definition whose class variable you wish to obtain.
 * @param name The name of the class variable definition to obtain.
 * 
 * @return A pointer to an \\\\c Ivar data structure containing information about the class variable specified by \\\\e name.
獲取類(lèi)成員變量的信息
 */
OBJC_EXPORT Ivar class_getClassVariable(Class cls, const char *name) 


/** 
 * Adds a new instance variable to a class.
 * 
 * @return YES if the instance variable was added successfully, otherwise NO 
 *         (for example, the class already contains an instance variable with that name).
 *
 * @note This function may only be called after objc_allocateClassPair and before objc_registerClassPair. 
 *       Adding an instance variable to an existing class is not supported.
 * @note The class must not be a metaclass. Adding an instance variable to a metaclass is not supported.
 * @note The instance variable's minimum alignment in bytes is 1<<align. The minimum alignment of an instance 
 *       variable depends on the ivar's type and the machine architecture. 
 *       For variables of any pointer type, pass log2(sizeof(pointer_type)).
添加成員變量
 */
OBJC_EXPORT BOOL class_addIvar(Class cls, const char *name, size_t size, 
                               uint8_t alignment, const char *types)

/** 
 * Describes the instance variables declared by a class.
 * 
 * @param cls The class to inspect.
 * @param outCount On return, contains the length of the returned array. 
 *  If outCount is NULL, the length is not returned.
 * 
 * @return An array of pointers of type Ivar describing the instance variables declared by the class. 
 *  Any instance variables declared by superclasses are not included. The array contains *outCount 
 *  pointers followed by a NULL terminator. You must free the array with free().
 * 
 *  If the class declares no instance variables, or cls is Nil, NULL is returned and *outCount is 0.

獲取整個(gè)成員變量列表, 返回是一個(gè)數(shù)組,outCount指針?lè)祷財(cái)?shù)組的大小
 */
OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

⑤ Property(屬性)操作函數(shù)

/** 
 * Returns a property with a given name of a given class.
 * 
 * @param cls The class you want to inspect.
 * @param name The name of the property you want to inspect.
 * 
 * @return A pointer of type \\\\c objc_property_t describing the property, or
 *  \\\\c NULL if the class does not declare a property with that name, 
 *  or \\\\c NULL if \\\\e cls is \\\\c Nil.
獲取指定屬性
 */
 objc_property_t class_getProperty(Class cls, const char *name)


/** 
 * Describes the properties declared by a class.
 * 
 * @param cls The class you want to inspect.
 * @param outCount On return, contains the length of the returned array. 
 *  If \\\\e outCount is \\\\c NULL, the length is not returned.        
 * 
 * @return An array of pointers of type \\\\c objc_property_t describing the properties 
 *  declared by the class. Any properties declared by superclasses are not included. 
 *  The array contains \\\\c *outCount pointers followed by a \\\\c NULL terminator. You must free the array with \\\\c free().
 * 
 *  If \\\\e cls declares no properties, or \\\\e cls is \\\\c Nil, returns \\\\c NULL and \\\\c *outCount is \\\\c 0.

獲取屬性列表,返回一個(gè)數(shù)組,outCount指針?lè)祷財(cái)?shù)組的大小
 */
 objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

/** 
 * Adds a property to a class.
 * 
 * @param cls The class to modify.
 * @param name The name of the property.
 * @param attributes An array of property attributes.
 * @param attributeCount The number of attributes in \\\\e attributes.
 * 
 * @return \\\\c YES if the property was added successfully, otherwise \\\\c NO
 *  (for example, the class already has that property).

為類(lèi)添加屬性
 */
OBJC_EXPORT BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)


/** 
 * Replace a property of a class. 
 * 
 * @param cls The class to modify.
 * @param name The name of the property.
 * @param attributes An array of property attributes.
 * @param attributeCount The number of attributes in \\\\e attributes. 

替換類(lèi)中的屬性
 */
 void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)

⑥ Method(方法)操作

/** 
 * Adds a new method to a class with a given name and implementation.
 * 
 * @param cls The class to which to add a method.
 * @param name A selector that specifies the name of the method being added.
 * @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
 * @param types An array of characters that describe the types of the arguments to the method. 
 * 
 * @return YES if the method was added successfully, otherwise NO 
 *  (for example, the class already contains a method implementation with that name).
 *
 * @note class_addMethod will add an override of a superclass's implementation, 
 *  but will not replace an existing implementation in this class. 
 *  To change an existing implementation, use method_setImplementation.

添加方法
 */
 BOOL class_addMethod(Class cls, SEL name, IMP imp, 
                                 const char *types)

/* 
* 獲取實(shí)例方法
*/
Method class_getInstanceMethod ( Class cls, SEL name );

 /* 
* 獲取類(lèi)方法
*/
Method class_getClassMethod ( Class cls, SEL name );

  /* 
* 獲取所有方法的數(shù)組
*/
Method * class_copyMethodList ( Class cls, unsigned int *outCount );

  /* 
* 替代方法的實(shí)現(xiàn)
*/
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );

  /* 
* 返回方法的具體實(shí)現(xiàn)
*/
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );

  /* 
* 類(lèi)實(shí)例是否響應(yīng)指定的selector
*/ 
BOOL class_respondsToSelector ( Class cls, SEL sel );

⑦ Version(版本)

// 獲取版本號(hào)
int class_getVersion ( Class cls );
 
// 設(shè)置版本號(hào)
void class_setVersion ( Class cls, int version );

實(shí)例將之后更新......

參考文獻(xiàn):hengshujiyi[Objective-C Runtime 運(yùn)行時(shí)之一:類(lèi)與對(duì)象]

Civel_Xu [runtime 運(yùn)行時(shí)機(jī)制 + 應(yīng)用場(chǎng)景]

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

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,041評(píng)論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,881評(píng)論 33 466
  • 前言 runtime其實(shí)在我們?nèi)粘i_(kāi)發(fā)過(guò)程中很少使用到,尤其是像我現(xiàn)在比較初級(jí)的程序猿就更用不到了。但是去面試很多...
    WolfTin閱讀 840評(píng)論 0 2
  • 原文出處:南峰子的技術(shù)博客 Objective-C語(yǔ)言是一門(mén)動(dòng)態(tài)語(yǔ)言,它將很多靜態(tài)語(yǔ)言在編譯和鏈接時(shí)期做的事放到了...
    _燴面_閱讀 1,406評(píng)論 1 5
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 828評(píng)論 0 2

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