文章分享至個人我的技術博客:https://cainluo.github.io/15033286127687.htmlhtml
RunTime
是Objective-C
的特性, 若是用別的話來講, 就是由於Objective-C
是動態語言, 而後RunTime
就是它的運行時機制這些這些, 而後就沒而後了...git
可是對於我這些渣渣來講, 我的認爲就是一堆C
語言寫的東西, 廢話少說了, 直接來擼吧.github
轉載聲明:如須要轉載該文章, 請聯繫做者, 而且註明出處, 以及不能擅自修改本文.web
在咱們日常的使用當中, 會常常聲明一個函數, 而後去調用, 但裏面作了什麼操做, 咱們並不知道, 如今咱們來看一段代碼:vim
#import "RunTimeModel.h"
#import <objc/message.h>
#import <objc/objc.h>
@implementation RunTimeModel
- (instancetype)init {
self = [super init];
if (self) {
[self sendMessage];
[self sendMessage:100];
}
return self;
}
- (void)sendMessage {
NSLog(@"Message");
}
- (void)sendMessage:(NSInteger)messageCount {
NSLog(@"Message: %ld", messageCount);
}
@end
複製代碼
這段代碼, 是咱們正常寫的Objective-C
代碼, 咱們能夠經過終端
的命令行, 進行重編:緩存
clang -rewrite-objc RunTimeModel.m
複製代碼
而後就會獲得一個RunTimeModel.cpp
的文件, 裏面有90000+
行代碼, 這裏面咱們要找到一段東西:bash
static instancetype _I_RunTimeModel_init(RunTimeModel * self, SEL _cmd) {
self = ((RunTimeModel *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("RunTimeModel"))}, sel_registerName("init"));
if (self) {
((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("sendMessage"));
((void (*)(id, SEL, NSInteger))(void *)objc_msgSend)((id)self, sel_registerName("sendMessage:"), (NSInteger)100);
}
return self;
}
複製代碼
((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("sendMessage"));
((void (*)(id, SEL, NSInteger))(void *)objc_msgSend)((id)self, sel_registerName("sendMessage:"), (NSInteger)100);
複製代碼
這就是咱們在.m
文件裏調用方法時所進行的操做, 會轉化成消息發送的形式進行通訊, objc_msgSend
是在#import <objc/message.h>
文件中, 聲明方式:微信
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
複製代碼
這裏是有兩個基礎參數, 分別是id
和SEL
.app
id
和SEL
都是定義在#include <objc/objc.h>
中:ide
typedef struct objc_object *id;
typedef struct objc_selector *SEL;
複製代碼
C
字符串, 咱們能夠用Objective-C
的@selector()
或者RunTime
裏的sel_registerName
來獲取一個SEL
類型的方法選擇器.Objective-C
中的任何對象.objc_object
定義:
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
複製代碼
其實這纔是對象原本的面貌, 不要給漂亮的外表給矇騙了咯.
這個結構體就只有一個isa
成員變量, 對象是能夠經過isa
指針找到本身所屬的類, 看到這裏, 咱們就不由疑惑, isa
是一個Class
的成員變量, 那Class
又是啥?
咱們在#include <objc/objc.h>
中實際上是有看到Class
的聲明:
typedef struct objc_class *Class;
複製代碼
但實際上Class
是定義在#include <objc/runtime.h>
中:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
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;
#endif
} OBJC2_UNAVAILABLE;
複製代碼
這裏解釋一下里面的東東:
isa
指針, 指向所屬的meta
(元類).Runtime
會把被調用的方法存到cache
中, 下次查找的時候效率更高, 其實就是這個方法第一次被調用了以後, 爲了之後還會被調用的可能而作的緩存.這裏的methodLists
須要注意一下, 它是指向objc_method_list
指針的指針, 也就是說能夠動態修改methodLists
的值來添加成員方法, 咱們常常用的Category
就是醬紫來的, 也由於這個東西, Category
通常是沒辦法添加屬性, 須要咱們本身寫寫寫.
看到這裏, 基本的東西咱們都差很少了解完了, 如今加個補刀, 看看整個運行的過程:
Runtime
會把咱們的方法調用
轉化爲消息發送
, 也就是咱們剛剛說的objc_msgSend
, 而且把方法的調用者和方法選擇器, 當作參數傳遞過去.isa
指針來找到方法所屬的類, 而後在cache
或者methodLists
查找被調用的方法, 找到了就跳轉到對應的方法去執行.
super_class
往更上一級的超類中查找, 查找到了就執行(若是找不到呢? 這個後面會有補充).說完這裏, 有些人確定會很奇怪, 這裏的methodLists
裝的是實例方法, 那類方法呢?
其實, 類方法是被存儲在元類中, Class
會經過isa
指針找到所屬的元類, 這些類方法就是存在這裏了, 具體怎麼獲取類方法, 咱們能夠看看代碼:
- (void)getClassMethods {
NSObject *obj = [[NSObject alloc] init];
unsigned int methodCount = 0;
const char *className = class_getName([obj class]);
Class metaClass = objc_getMetaClass(className);
Method *methodList = class_copyMethodList(metaClass, &methodCount);
for (int i = 0; i < methodCount; i++) {
Method method = methodList[i];
SEL selector = method_getName(method);
const char *methodName = sel_getName(selector);
NSLog(@"%s", methodName);
}
}
複製代碼
打印出來的結果:vim
2017-08-22 13:24:19.455 1.RunTime[32885:2667202] _installAppearanceSwizzlesForSetter:
2017-08-22 13:24:19.456 1.RunTime[32885:2667202] __accessibilityGuidedAccessStateEnabled
2017-08-22 13:24:19.456 1.RunTime[32885:2667202] __accessibilityGuidedAccessRestrictionStateForIdentifier:
2017-08-22 13:24:19.456 1.RunTime[32885:2667202] __accessibilityRequestGuidedAccessSession:completion:
2017-08-22 13:24:19.456 1.RunTime[32885:2667202] isSelectorExcludedFromWebScript:
2017-08-22 13:24:19.457 1.RunTime[32885:2667202] isKeyExcludedFromWebScript:
2017-08-22 13:24:19.457 1.RunTime[32885:2667202] _webkit_invokeOnMainThread
2017-08-22 13:24:19.457 1.RunTime[32885:2667202] sbs_dataFromObject:
2017-08-22 13:24:19.457 1.RunTime[32885:2667202] sbs_objectFromData:
2017-08-22 13:24:19.458 1.RunTime[32885:2667202] sbs_dataWithValue:
2017-08-22 13:24:19.458 1.RunTime[32885:2667202] sbs_valueFromData:ofType:
2017-08-22 13:24:19.458 1.RunTime[32885:2667202] CA_automaticallyNotifiesObservers:
2017-08-22 13:24:19.459 1.RunTime[32885:2667202] CA_setterForProperty:
2017-08-22 13:24:19.459 1.RunTime[32885:2667202] CA_getterForProperty:
2017-08-22 13:24:19.459 1.RunTime[32885:2667202] CA_encodesPropertyConditionally:type:
2017-08-22 13:24:19.459 1.RunTime[32885:2667202] CA_CAMLPropertyForKey:
2017-08-22 13:24:19.459 1.RunTime[32885:2667202] bs_decodedFromData:
2017-08-22 13:24:19.460 1.RunTime[32885:2667202] bs_objectFromData:
2017-08-22 13:24:19.460 1.RunTime[32885:2667202] bs_secureObjectFromData:ofClass:
2017-08-22 13:24:19.460 1.RunTime[32885:2667202] bs_secureObjectFromData:ofClasses:
2017-08-22 13:24:19.460 1.RunTime[32885:2667202] bs_synchronousWrapper:timeout:
2017-08-22 13:24:19.460 1.RunTime[32885:2667202] bs_secureDataFromObject:
2017-08-22 13:24:19.461 1.RunTime[32885:2667202] bs_dataFromObject:
2017-08-22 13:24:19.461 1.RunTime[32885:2667202] bs_secureDecodedFromData:withAdditionalClasses:
2017-08-22 13:24:19.461 1.RunTime[32885:2667202] bs_secureDecodedFromData:
2017-08-22 13:24:19.506 1.RunTime[32885:2667202] replacementObjectForPortCoder:
2017-08-22 13:24:19.506 1.RunTime[32885:2667202] instanceMethodDescriptionForSelector:
2017-08-22 13:24:19.507 1.RunTime[32885:2667202] methodDescriptionForSelector:
2017-08-22 13:24:19.507 1.RunTime[32885:2667202] _localClassNameForClass
2017-08-22 13:24:19.507 1.RunTime[32885:2667202] cancelPreviousPerformRequestsWithTarget:selector:object:
2017-08-22 13:24:19.507 1.RunTime[32885:2667202] cancelPreviousPerformRequestsWithTarget:
2017-08-22 13:24:19.507 1.RunTime[32885:2667202] setVersion:
2017-08-22 13:24:19.508 1.RunTime[32885:2667202] implementsSelector:
2017-08-22 13:24:19.508 1.RunTime[32885:2667202] instancesImplementSelector:
2017-08-22 13:24:19.508 1.RunTime[32885:2667202] load
2017-08-22 13:24:19.508 1.RunTime[32885:2667202] version
2017-08-22 13:24:19.509 1.RunTime[32885:2667202] classForKeyedUnarchiver
2017-08-22 13:24:19.509 1.RunTime[32885:2667202] classFallbacksForKeyedArchiver
2017-08-22 13:24:19.509 1.RunTime[32885:2667202] _shouldAddObservationForwardersForKey:
2017-08-22 13:24:19.509 1.RunTime[32885:2667202] setKeys:triggerChangeNotificationsForDependentKey:
2017-08-22 13:24:19.510 1.RunTime[32885:2667202] automaticallyNotifiesObserversForKey:
2017-08-22 13:24:19.510 1.RunTime[32885:2667202] _keysForValuesAffectingValueForKey:
2017-08-22 13:24:19.510 1.RunTime[32885:2667202] keyPathsForValuesAffectingValueForKey:
2017-08-22 13:24:19.510 1.RunTime[32885:2667202] _createValueGetterWithContainerClassID:key:
2017-08-22 13:24:19.511 1.RunTime[32885:2667202] _createValueSetterWithContainerClassID:key:
2017-08-22 13:24:19.511 1.RunTime[32885:2667202] _createMutableOrderedSetValueGetterWithContainerClassID:key:
2017-08-22 13:24:19.511 1.RunTime[32885:2667202] _createMutableSetValueGetterWithContainerClassID:key:
2017-08-22 13:24:19.511 1.RunTime[32885:2667202] _createValuePrimitiveGetterWithContainerClassID:key:
2017-08-22 13:24:19.512 1.RunTime[32885:2667202] _createValuePrimitiveSetterWithContainerClassID:key:
2017-08-22 13:24:19.512 1.RunTime[32885:2667202] _createOtherValueGetterWithContainerClassID:key:
2017-08-22 13:24:19.512 1.RunTime[32885:2667202] _createOtherValueSetterWithContainerClassID:key:
2017-08-22 13:24:19.512 1.RunTime[32885:2667202] _createMutableArrayValueGetterWithContainerClassID:key:
2017-08-22 13:24:19.513 1.RunTime[32885:2667202] accessInstanceVariablesDirectly
2017-08-22 13:24:19.513 1.RunTime[32885:2667202] instanceMethodSignatureForSelector:
2017-08-22 13:24:19.513 1.RunTime[32885:2667202] load
2017-08-22 13:24:19.513 1.RunTime[32885:2667202] dealloc
2017-08-22 13:24:19.514 1.RunTime[32885:2667202] doesNotRecognizeSelector:
2017-08-22 13:24:19.514 1.RunTime[32885:2667202] description
2017-08-22 13:24:19.514 1.RunTime[32885:2667202] methodSignatureForSelector:
2017-08-22 13:24:19.514 1.RunTime[32885:2667202] __allocWithZone_OA:
2017-08-22 13:24:19.515 1.RunTime[32885:2667202] _copyDescription
2017-08-22 13:24:19.515 1.RunTime[32885:2667202] init
2017-08-22 13:24:19.515 1.RunTime[32885:2667202] zone
2017-08-22 13:24:19.515 1.RunTime[32885:2667202] instancesRespondToSelector:
2017-08-22 13:24:19.516 1.RunTime[32885:2667202] instanceMethodForSelector:
2017-08-22 13:24:19.516 1.RunTime[32885:2667202] isAncestorOfObject:
2017-08-22 13:24:19.516 1.RunTime[32885:2667202] instanceMethodSignatureForSelector:
2017-08-22 13:24:19.516 1.RunTime[32885:2667202] load
2017-08-22 13:24:19.517 1.RunTime[32885:2667202] initialize
2017-08-22 13:24:19.517 1.RunTime[32885:2667202] resolveInstanceMethod:
2017-08-22 13:24:19.517 1.RunTime[32885:2667202] resolveClassMethod:
2017-08-22 13:24:19.517 1.RunTime[32885:2667202] retain
2017-08-22 13:24:19.518 1.RunTime[32885:2667202] release
2017-08-22 13:24:19.518 1.RunTime[32885:2667202] autorelease
2017-08-22 13:24:19.518 1.RunTime[32885:2667202] retainCount
2017-08-22 13:24:19.518 1.RunTime[32885:2667202] alloc
2017-08-22 13:24:19.519 1.RunTime[32885:2667202] allocWithZone:
2017-08-22 13:24:19.519 1.RunTime[32885:2667202] dealloc
2017-08-22 13:24:19.519 1.RunTime[32885:2667202] copy
2017-08-22 13:24:19.519 1.RunTime[32885:2667202] new
2017-08-22 13:24:19.520 1.RunTime[32885:2667202] forwardInvocation:
2017-08-22 13:24:19.520 1.RunTime[32885:2667202] _tryRetain
2017-08-22 13:24:19.520 1.RunTime[32885:2667202] _isDeallocating
2017-08-22 13:24:19.520 1.RunTime[32885:2667202] retainWeakReference
2017-08-22 13:24:19.521 1.RunTime[32885:2667202] allowsWeakReference
2017-08-22 13:24:19.521 1.RunTime[32885:2667202] copyWithZone:
2017-08-22 13:24:19.521 1.RunTime[32885:2667202] mutableCopyWithZone:
2017-08-22 13:24:19.522 1.RunTime[32885:2667202] doesNotRecognizeSelector:
2017-08-22 13:24:19.522 1.RunTime[32885:2667202] description
2017-08-22 13:24:19.522 1.RunTime[32885:2667202] isFault
2017-08-22 13:24:19.522 1.RunTime[32885:2667202] mutableCopy
2017-08-22 13:24:19.523 1.RunTime[32885:2667202] performSelector:withObject:
2017-08-22 13:24:19.523 1.RunTime[32885:2667202] isMemberOfClass:
2017-08-22 13:24:19.524 1.RunTime[32885:2667202] hash
2017-08-22 13:24:19.524 1.RunTime[32885:2667202] isEqual:
2017-08-22 13:24:19.524 1.RunTime[32885:2667202] self
2017-08-22 13:24:19.524 1.RunTime[32885:2667202] performSelector:
2017-08-22 13:24:19.525 1.RunTime[32885:2667202] conformsToProtocol:
2017-08-22 13:24:19.525 1.RunTime[32885:2667202] methodSignatureForSelector:
2017-08-22 13:24:19.525 1.RunTime[32885:2667202] forwardingTargetForSelector:
2017-08-22 13:24:19.525 1.RunTime[32885:2667202] methodForSelector:
2017-08-22 13:24:19.526 1.RunTime[32885:2667202] performSelector:withObject:withObject:
2017-08-22 13:24:19.526 1.RunTime[32885:2667202] superclass
2017-08-22 13:24:19.526 1.RunTime[32885:2667202] isSubclassOfClass:
2017-08-22 13:24:19.527 1.RunTime[32885:2667202] class
2017-08-22 13:24:19.527 1.RunTime[32885:2667202] init
2017-08-22 13:24:19.528 1.RunTime[32885:2667202] debugDescription
2017-08-22 13:24:19.528 1.RunTime[32885:2667202] isProxy
2017-08-22 13:24:19.529 1.RunTime[32885:2667202] respondsToSelector:
2017-08-22 13:24:19.529 1.RunTime[32885:2667202] isKindOfClass:
複製代碼
這裏順帶補充一下isa
指針的指向:
類
的isa
指針指向的是元類
.元類
的isa
指針指向的是根類
.根類
或者是元類
的超類是NSObject
, 那麼就是指向本身.NSObject
是沒有超類的.項目地址: https://github.com/CainRun/iOS-Project-Example/tree/master/RunTime/玩轉iOS開發:iOS中的RunTime(一)
注意: RunTimeModel.cpp
在目錄中, 我並無放到工程裏.