參考:
代碼地址:https://opensource.apple.com/tarballs/objc4/
文檔地址:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008048-CH1-SW1
https://developer.apple.com/documentation/objectivec?language=objc
Overview(概述)
The Objective-C Runtime module APIs define the base of the Objective-C language. These APIs include:(Objective-C運(yùn)行時(shí)模塊api定義了Objective-C語(yǔ)言的基礎(chǔ)两踏。這些api包括:)
- Types such as the
NSObject
class and theNSObject
protocol that provide the root functionality of most Objective-C classes(類(lèi)型梦染,如NSObject類(lèi)和NSObject協(xié)議,它們提供了大多數(shù)Objective-C類(lèi)的根功能)- Functions and data structures that comprise the Objective-C runtime, which provides support for the dynamic properties of the Objective-C language(包含Objective-C運(yùn)行時(shí)的函數(shù)和數(shù)據(jù)結(jié)構(gòu)泛粹,它支持Objective-C語(yǔ)言的動(dòng)態(tài)屬性)
You typically don't need to use this module directly.(通常不需要直接使用此模塊晶姊。)
objc_object
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
objc_class
typedef struct objc_class *Class;
struct objc_class {
//結(jié)構(gòu)體的第一個(gè)成員變量也是isa指針伪货,這就說(shuō)明了Class本身其實(shí)也是一個(gè)對(duì)象碱呼,因此我們稱(chēng)之為類(lèi)對(duì)象巍举,類(lèi)對(duì)象在編譯期產(chǎn)生用于創(chuàng)建實(shí)例對(duì)象,是單例蜓谋。
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
objc_method_list
struct objc_method_list {
struct objc_method_list * _Nullable 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;
}
Method(objc_method)
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;
struct objc_method {
SEL _Nonnull method_name OBJC2_UNAVAILABLE;
//方法的參數(shù)類(lèi)型和返回值類(lèi)型。
char * _Nullable method_types OBJC2_UNAVAILABLE;
//方法的實(shí)現(xiàn)观堂,本質(zhì)上是一個(gè)函數(shù)指針
IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
}
objc_cache
//cache為方法調(diào)用的性能進(jìn)行優(yōu)化呀忧,通俗的講而账,每當(dāng)實(shí)例對(duì)象接收到一個(gè)消息時(shí)候,它不會(huì)直接在isa指向的類(lèi)方法的方法列表中遍歷查找能夠響應(yīng)消息的方法笔横,效率太低了吹缔,而是有限在cache中查找锯茄。Runtime系統(tǒng)會(huì)把被調(diào)用的方法存在cache中,下次查找的時(shí)候效率更高俗冻。
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method _Nullable buckets[1] OBJC2_UNAVAILABLE;
};
SEL(objc_selector)
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
objc_msgSend函數(shù)第二個(gè)參數(shù)類(lèi)型為SEL迄薄,它是selector在Objective-C中的表示類(lèi)型
- 同一個(gè)類(lèi)讥蔽,selector不能重復(fù)
- 不同的類(lèi),selector可以重復(fù)
IMP
/// A pointer to the function of a method implementation. 指向一個(gè)方法實(shí)現(xiàn)的指針
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
Category(objc_category)
//分類(lèi)中可以添加實(shí)例方法新症,類(lèi)方法徒爹,甚至可以實(shí)現(xiàn)協(xié)議隆嗅,添加屬性胖喳,不可以添加成員變量。
struct category_t {
//是指 class_name 而不是 category_name技健。
const char *name;
//要擴(kuò)展的類(lèi)對(duì)象顷级,編譯期間是不會(huì)定義的弓颈,而是在Runtime階段通過(guò)name對(duì) 應(yīng)到對(duì)應(yīng)的類(lèi)對(duì)象翔冀。
classref_t cls;
struct method_list_t *instanceMethods;
//category中所有添加的類(lèi)方法的列表纤子。
struct method_list_t *classMethods;
//category實(shí)現(xiàn)的所有協(xié)議的列表控硼。
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
// Fields below this point are not always present on disk.
struct property_list_t *_classProperties;
method_list_t *methodsForMeta(bool isMeta) {
if (isMeta) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
Ivar(objc_ivar)
typedef struct objc_ivar *Ivar;
//表示類(lèi)中實(shí)例變量的類(lèi)型,objc_ivar可以根據(jù)實(shí)例查找其在類(lèi)中的名字卡乾,也就是“反射”;
struct objc_ivar {
char * _Nullable ivar_name OBJC2_UNAVAILABLE;
char * _Nullable ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
objc_property_t
//@property標(biāo)記了類(lèi)中的屬性幔妨,它是一個(gè)指向objc_property結(jié)構(gòu)體的指針:
typedef struct objc_property *objc_property_t;
//通過(guò)class_copyPropertyList和protocol_copyPropertyList方法來(lái)獲取類(lèi)和協(xié)議中的屬性
OBJC_EXPORT objc_property_t _Nonnull * _Nullable
class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_EXPORT objc_property_t _Nonnull * _Nullable
protocol_copyPropertyList(Protocol * _Nonnull proto,
unsigned int * _Nullable outCount)
unsigned int number = 0
objc_property_t *propertys = class_copyPropertyList([self class], &number);
for (int i = 0; i < number; i ++) {
objc_property_t property = propertys[i];
const char *name = property_getName(property);
const char *type = property_getAttributes(property);
NSString *nameStr = [NSString stringWithUTF8String:name];
NSString *typeStr = [NSString stringWithUTF8String:type];
NSLog(@"name === %@ type === %@", nameStr, typeStr);
}
objec_msgSend
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
消息機(jī)制
The objc_msgSend Function
In Objective-C, messages aren’t bound to method implementations until runtime. The compiler converts a message expression,(在Objective-C中古话,消息直到運(yùn)行時(shí)才綁定到方法實(shí)現(xiàn)陪踩。編譯器轉(zhuǎn)換消息表達(dá)式肩狂,)
[receiver message]
into a call on a messaging function, objc_msgSend. This function takes the receiver and the name of the method mentioned in the message—that is, the method selector—as its two principal parameters:(調(diào)用消息傳遞函數(shù)objc_msgSend婚温。該函數(shù)將接收方和消息中提到的方法名稱(chēng)(即方法選擇器)作為其兩個(gè)主要參數(shù):)
Any arguments passed in the message are also handed to objc_msgSend:(在消息中傳遞的任何參數(shù)也會(huì)傳遞給objc_msgSend:)
objc_msgSend(receiver, selector, arg1, arg2, ...)
The messaging function does everything necessary for dynamic binding:(消息傳遞函數(shù)執(zhí)行動(dòng)態(tài)綁定所需的所有操作:)
It first finds the procedure (method implementation) that the selector refers to. Since the same method can be implemented differently by separate classes, the precise procedure that it finds depends on the class of the receiver.(它首先找到選擇器引用的過(guò)程(方法實(shí)現(xiàn))。由于相同的方法可以由不同的類(lèi)以不同的方式實(shí)現(xiàn)力图,所以它找到的精確過(guò)程取決于接收者的類(lèi)吃媒。)
It then calls the procedure, passing it the receiving object (a pointer to its data), along with any arguments that were specified for the method.(然后調(diào)用該過(guò)程赘那,將接收對(duì)象(指向其數(shù)據(jù)的指針)以及為該方法指定的任何參數(shù)傳遞給它。)
Finally, it passes on the return value of the procedure as its own return value.(最后,它將過(guò)程的返回值作為自己的返回值傳遞拱礁。)
Note: The compiler generates calls to the messaging function. You should never call it directly in the code you write.(注意:編譯器生成對(duì)消息傳遞函數(shù)的調(diào)用呢灶。在編寫(xiě)代碼時(shí)鸯乃,永遠(yuǎn)不要直接調(diào)用它)
When a message is sent to an object, the messaging function follows the object’s
isa
pointer to the class structure where it looks up the method selector in the dispatch table. If it can’t find the selector there, objc_msgSend
follows the pointer to the superclass and tries to find the selector in its dispatch table. Successive failures cause objc_msgSend
to climb the class hierarchy until it reaches the NSObject
class. Once it locates the selector, the function calls the method entered in the table and passes it the receiving object’s data structure.(當(dāng)消息被發(fā)送到對(duì)象時(shí)赘娄,消息傳遞函數(shù)遵循對(duì)象的isa指針指向類(lèi)結(jié)構(gòu)遣臼,在這個(gè)類(lèi)結(jié)構(gòu)中揍堰,它在分派表中查找方法選擇器屏歹。如果在那里找不到選擇器蝙眶,objc_msgSend會(huì)跟隨指向超類(lèi)的指針褪那,并嘗試在其分派表中找到選擇器。連續(xù)的失敗導(dǎo)致objc_msgSend爬上類(lèi)層次結(jié)構(gòu)博敬,直到它到達(dá)NSObject類(lèi)偏窝。一旦找到選擇器祭往,函數(shù)就調(diào)用表中輸入的方法默赂,并將接收對(duì)象的數(shù)據(jù)結(jié)構(gòu)傳遞給它缆八。)
This is the way that method implementations are chosen at runtime—or, in the jargon of object-oriented programming, that methods are dynamically bound to messages.(這就是在運(yùn)行時(shí)選擇方法實(shí)現(xiàn)的方法—或者,用面向?qū)ο缶幊痰男g(shù)語(yǔ)來(lái)說(shuō)奖恰,方法是動(dòng)態(tài)綁定到消息的方法瑟啃。)
To speed the messaging process, the runtime system caches the selectors and addresses of methods as they are used. There’s a separate cache for each class, and it can contain selectors for inherited methods as well as for methods defined in the class. Before searching the dispatch tables, the messaging routine first checks the cache of the receiving object’s class (on the theory that a method that was used once may likely be used again). If the method selector is in the cache, messaging is only slightly slower than a function call. Once a program has been running long enough to “warm up” its caches, almost all the messages it sends find a cached method. Caches grow dynamically to accommodate new messages as the program runs.(為了加快消息傳遞過(guò)程,運(yùn)行時(shí)系統(tǒng)在使用選擇器和方法地址時(shí)緩存它們。每個(gè)類(lèi)都有一個(gè)單獨(dú)的緩存犹撒,它可以包含繼承方法和類(lèi)中定義的方法的選擇器。在搜索分派表之前祥款,消息傳遞例程首先檢查接收對(duì)象的類(lèi)的緩存(理論上镰踏,使用過(guò)一次的方法可能會(huì)再次使用)。如果方法選擇器在緩存中绊率,消息傳遞只比函數(shù)調(diào)用稍微慢一點(diǎn)。一旦一個(gè)程序運(yùn)行了足夠長(zhǎng)的時(shí)間來(lái)“預(yù)熱”它的緩存藐俺,它發(fā)送的幾乎所有消息都會(huì)找到一個(gè)緩存的方法卿啡。緩存在程序運(yùn)行時(shí)動(dòng)態(tài)增長(zhǎng)颈娜,以適應(yīng)新的消息。)
消息傳遞
- 系統(tǒng)首先找到消息的接收對(duì)象同仆,然后通過(guò)對(duì)象的isa找到它的類(lèi)。
- 在它的類(lèi)中查找method_list扶镀,是否有selector方法(先查緩存)。
- 沒(méi)有則查找父類(lèi)的method_list。
- 找到對(duì)應(yīng)的method什乙,執(zhí)行它的IMP。
- 轉(zhuǎn)發(fā)IMP的return值忆某。
實(shí)例、類(lèi)聋呢、父類(lèi)徒探、元央串、根元類(lèi)
類(lèi)對(duì)象就是一個(gè)結(jié)構(gòu)體struct objc_class,這個(gè)結(jié)構(gòu)體存放的數(shù)據(jù)稱(chēng)為元數(shù)據(jù)(metadata)厦酬,
類(lèi)對(duì)象中的元數(shù)據(jù)存儲(chǔ)的都是如何創(chuàng)建一個(gè)實(shí)例的相關(guān)信息,類(lèi)對(duì)象和類(lèi)方法就是從isa指針指向的結(jié)構(gòu)體創(chuàng)建,類(lèi)對(duì)象的isa指針指向的我們稱(chēng)之為元類(lèi)(metaclass)筹裕,
struct objc_object結(jié)構(gòu)體實(shí)例它的isa指針指向類(lèi)對(duì)象乐埠,
類(lèi)對(duì)象的isa指針指向了元類(lèi)豪治,super_class指針指向了父類(lèi)的類(lèi)對(duì)象,
而元類(lèi)的super_class指針指向了父類(lèi)的元類(lèi)花吟,那元類(lèi)的isa指針又指向了自己。
元類(lèi)(Meta Class)是一個(gè)類(lèi)對(duì)象的類(lèi)今布。
在上面我們提到造虎,所有的類(lèi)自身也是一個(gè)對(duì)象份蝴,我們可以向這個(gè)對(duì)象發(fā)送消息(即調(diào)用類(lèi)方法)。
為了調(diào)用類(lèi)方法,這個(gè)類(lèi)的isa指針必須指向一個(gè)包含這些類(lèi)方法的一個(gè)objc_class結(jié)構(gòu)體。這就引出了meta-class的概念匣椰,元類(lèi)中保存了創(chuàng)建類(lèi)對(duì)象以及類(lèi)方法所需的所有信息蛤奥。
任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己的所屬類(lèi),而根類(lèi)的meta-class的isa指針是指向它自己啊掏。
Using Hidden Arguments(兩個(gè)隱藏參數(shù))
- The receiving object(接收的實(shí)例對(duì)象)
- The selector for the method(方法選擇器SEL)
Dynamic Method Resolution(動(dòng)態(tài)方法解析)
文檔地址:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtDynamicResolution.html#//apple_ref/doc/uid/TP40008048-CH102-SW1
void dynamicMethodIMP(id self, SEL _cmd) {
// implementation ....
}
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
@end
Message Forwarding(消息轉(zhuǎn)發(fā))
文檔地址:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105-SW1
- 重定向髓霞,使用備用接收者
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(foo)) {
return [Person new];//返回Person對(duì)象兢交,讓Person對(duì)象接收這個(gè)消息
}
return [super forwardingTargetForSelector:aSelector];
}
- 完整消息轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];//簽名晴裹,進(jìn)入forwardInvocation
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = anInvocation.selector;
Person *p = [Person new];
if([p respondsToSelector:sel]) {
[anInvocation invokeWithTarget:p];
}
else {
[self doesNotRecognizeSelector:sel];
}
}