iOS Runtime详解
Objective-C Runtime的源码世界深藏了高效的消息传递机制和动态扩展的能力。它以C和汇编的编译形式构建,为iOS .5+的源码位程序提供了强大的扩展支持。日常开发中,编译我们主要依赖官方API,源码但理解Runtime的编译北京源码躁动科技底层运作有助于我们更好地利用它。
首先,源码理解类、编译实例和元类是源码关键。类由objc_class表示,编译作为单例的源码元类,isa指针揭示了类的编译本质。实例(objc_object)是源码梦境online源码类的具体实例,isa指向其对应的编译类。在消息传递中,源码我们通过isa查找类,遍历method_list找到目标IMP执行。
objc_msgSend是消息传递的核心,其语法[id self,51俱乐部源码 SEL op, ...]包含了对象、类和方法的选择。Message接收流程涉及类查找、method_list遍历,遇到未找到的方法时,会进行转发,优化了效率,python页面源码常用方法被缓存在objc_cache中。
元类负责类的创建,类方法和实例方法的管理,形成类的自包含结构。方法的定义包含SEL选择器和IMP实现,如"- (void)caculateWithInt:(NSInteger)num"通过SEL区分不同参数的触点云源码版本。
Category则为类添加动态功能,方法查找包括类自身、继承链,如果未找到则启动转发机制,经历动态方法解析和完整消息转发,为编程提供了灵活性。
例如,通过NSInvocation和MethodSignature,我们可以实现动态解析和消息转发。如ViewController转发foo给Person对象,处理未实现的方法。而关联对象(Objective-C Associated Objects)则通过objc_setAssociatedObject和objc_getAssociatedObject实现属性的动态绑定。
Runtime的魔法,如Method Swizzling,允许在运行时交换方法实现,KVO则通过动态创建子类来实现属性变化的监听。此外,如JSPatch和NSCoding/MJExtension等工具,利用Runtime扩展框架功能,动态修复bug和高效地操作对象属性。
综上所述,Objective-C Runtime是一个强大的工具,它潜藏在iOS开发的幕后,为动态扩展和高效编程提供了无限可能。深入理解并善用Runtime,将极大提升你的iOS开发能力。
iOS Runtimeç解
runtime
æ¦è¿°: runtimeåå«è¿è¡æ¶ï¼æ¯ä¸å¥åºå±Cè¯è¨APIï¼æ¯iOSç³»ç»çæ ¸å¿ä¹ä¸ãå¼åè å¨ç¼ç è¿ç¨ä¸ï¼å¯ä»¥ç»ä»»æä¸ä¸ªå¯¹è±¡åéæ¶æ¯ï¼å¨ç¼è¯é¶æ®µåªæ¯ç¡®å®äºè¦åæ¥åçåéè¿æ¡æ¶æ¯ï¼èæ¥åè å¦ä½ååºåå¤çè¿æ¡æ¶æ¯ï¼å°±è¦çè¿è¡æ¶æ¥å³å®äº
Cè¯è¨ä¸ï¼å¨ç¼è¯å¨å°±ç¡®å®è¦è°ç¨åªä¸ªå½æ°ï¼èOCçå½æ°ï¼å±äºå¨æè°ç¨è¿ç¨ï¼å¨ç¼è¯å¨å¹¶ä¸è½çæ£å³å®è°ç¨åªä¸ªå½æ°ï¼åªæå¨çæ£çè¿è¡æ¶æä¼æ ¹æ®å½æ°çå称æ¾å°å¯¹åºçå½æ°æ¥è°ç¨ãOCæ¯ä¸ä¸ªå¨æè¯è¨ï¼è¿æå³çå®ä¸ä» è¦ä¸ä¸ªç¼è¯å¨ï¼ä¹éè¦ä¸ä¸ªè¿è¡æ¶ç³»ç»æ¥å¨æå建类å对象ãè¿è¡æ¶æ¯ä¼ éååé
1.æ¶æ¯è½¬å
Runtimeçç¹æ§ä¸»è¦æ¯æ¶æ¯ä¼ éï¼å¦ææ¶æ¯å¨å¯¹è±¡ä¸æ¾ä¸å°ï¼å°±è¿è¡è½¬åãObjective-Cæ¯ä¸ä¸ªå¨æè¯è¨ï¼è¿æå³çå®ä¸ä» éè¦ä¸ä¸ªç¼è¯å¨ï¼ä¹éè¦ä¸ä¸ªè¿è¡æ¶ç³»ç»æ¥å¨æå建类å对象ãè¿è¡æ¶æ¯ä¼ éå转åãRuntimeçæ ¸å¿æ¯æ¶æ¯ä¼ éã
(1)æ¶æ¯ä¼ éçè¿ç¨
ä¸ä¸ªå¯¹è±¡çæ¹æ³[obj test],ç¼è¯å¨è½¬ææ¶æ¯åéobjc_msgSend(obj,test),Runtimeæ§è¡çæµç¨æ¯è¿æ ·ç
a.é¦å éè¿objçisaæéæ¾å°å®çclass
b.å¨classçmethod listæ¾test
c.å¦æclassä¸æ²¡æ¾å°testï¼ç»§ç»å¾å®çsuperclassä¸æ¾
d.ä¸æ¦æ¾å°testè¿ä¸ªå½æ°ï¼å°±å»æ§è¡å®çIMP
ç±äºæçé®é¢ï¼æ¯ä¸ªæ¶æ¯é½éåä¸æ¬¡objc_method_list并ä¸åçï¼æ以éè¦æç»å¸¸è¢«è°ç¨çå½æ°ç¼åä¸æ¥ï¼å»æé«å½æ°æ¥è¯¢çæçãè¿ä¹å°±æ¯objc_classä¸å¦ä¸ä¸ªéè¦çæåobjc_cacheåçäºæ ãæ¾å°testä¹åï¼å°testçmethod_nameä½ä¸ºkeyï¼method_impä½ä¸ºvalueãå½å次æ¶å°testæ¶æ¯çæ¶åï¼å¯ä»¥ç´æ¥å¨cacheéæ¾ã
类对象ï¼objc_classï¼
Objective-Cç±»æ¯ç±Classç±»åæ¥è¡¨ç¤ºçï¼å®å®é ä¸æ¯ä¸ä¸ªæåobjc_classç»æä½çæéãstruct objc_classç»æä½éé¢å®ä¹äºå¾å¤åéãç»æä½éä¿åäºæåç¶ç±»çæéãç±»çååï¼nameï¼ãçæ¬ãå®ä¾åéå表ï¼ivarsï¼ãæ¹æ³å表ï¼methodListsï¼ãç¼åï¼cacheï¼ãéµå®çåè®®å表ï¼protocolsï¼,ç±æ¤å¯è§ï¼ç±»å¯¹è±¡å°±æ¯ä¸ä¸ªç»æä½struct objc_classï¼è¿ä¸ªç»æä½åæ¾çæ°æ®å°±æ¯å æ°æ®
ç解Runtimeå°±æ¯ç解iOSå¨è¿è¡æ¶ä»çæ°æ®åå¨ä»¥åä»çç±»ãå®ä¾ã类对象ãå 类她们ä¹é´çå ³ç³»åä½ç¨ã
(2)æ¶æ¯è½¬åæºå¶
å½æ ¹å°åºï¼Objective-Cä¸ææçæ¹æ³è°ç¨æ¬è´¨å°±æ¯å对象åéæ¶æ¯
1.ç±»ä¸å建æ¹æ³-(void)test
2.iOSç³»ç»ä¸ºè¿ä¸ªæ¹æ³å建ä¸ä¸ªç¼å·ï¼SEL(test)并添å å°æ¹æ³å表éé¢
3.å½è°ç¨è¿ä¸ªæ¹æ³çæ¶åç³»ç»å»æ¹æ³å表éæ¥æ¾è¿ä¸ªæ¹æ³ï¼æ¾å°äºå°±æ§è¡
æ以ï¼è°ç¨ä¸ä¸ªæ¹æ³å°±ä¼è¿è¡ä¸æ¬¡åéæ¶æ¯ä¹å°±æ¯å¨è¿ä¸ªç±»çæ¹æ³å表éæ¾ï¼å¦æå¨è¯¥ç±»ä¸æ¾ä¸å°å°±å°è¯¥ç±»çç¶ç±»éæ¾ï¼å¦æç¶ç±»è¿æ¾ä¸å°å°±ä¸ç´æç´¢å°ç»§æ¿æ çæ ¹é¨ï¼å¦ææ¾ä¸å°æè æ¶æ¯è½¬åä¸æåé£å°±ä¼æ¥unrecognized selectoréã
1.å¨ææ¹æ³è§£æ
Objective-Cè¿è¡æ¶ä¼è°ç¨+resolveInstanceMethod:æè +resolveClassMethod:è®©ä½ ææºä¼æä¾ä¸ä¸ªå½æ°å®ç°ï¼å¦æä½ æ·»å äºå½æ°å¹¶ä¸è¿åYESï¼é£ä¹è¿è¡æ¶å°±ä¼éæ°å¯å¨ä¸æ¬¡æ¶æ¯åéçè¿ç¨ãå¦ä¸å¾ï¼
è½ç¶æ²¡æfoo:çå®ç°å½æ°ï¼ä½æ¯éè¿class_addMethod()å¨ææ·»å äºfooMethodå½æ°ï¼å¹¶æ§è¡äºè¿ä¸ªå½æ°å¹¶ä¸æå°æåãå¦æresloveè¿åNOè¿è¡æ¶å°±ä¼ç§»å°ä¸ä¸æ¥:forwardingTargetSelector
2.ç´æ¥æ¶æ¯è½¬å
å¦æç®æ 对象å®ç°äºforwardingTargetSelectorï¼Runtimeè¿æ¶å°±ä¼è°ç¨è¿ä¸ªæ¹æ³ï¼ç»ä½ æè¿ä¸ªæ¶æ¯è½¬åç»å ¶ä»å¯¹è±¡çæºä¼
ä»å¾ä¸å¯ä»¥çåºæ们éè¿forwardingTargetForSelectoræ¹æ³å°å½åç±»çæ¹æ³è½¬ç»Fatherç±»å®ç°äºï¼æå°æåã
3.å®æ´æ¶æ¯è½¬å
å¦æå¨ä¸ä¸æ¥è¿ä¸è½å¤çæªç¥æ¶æ¯ï¼é£å¯ä¸è½åçå°±æ¯å¯å¨æ¶æ¯è½¬åæºå¶ãé¦å å®ä¼åémethodSignatureForSelectoræ¶æ¯è·å¾å½æ°çåæ°åè¿åå¼ç±»åãå¦æmethodSignatureForSelectorè¿ånilï¼Runtimeåä¼ååºdoesNotRecognizeSelectorãå¦æè¿åä¸ä¸ªç¾åå½æ°ï¼Runtimeå°±ä¼å建ä¸ä¸ªNSInvocation对象并åéforwardInvocationæ¶æ¯ç»ç®æ 对象ã
Runtimeçå®é åºç¨
1.使ç¨Runtime交æ¢æ¹æ³
2.å¨ææ·»å æ¹æ³ï¼ç®åä¸æ¯å¾æï¼
3.ç»å类添å å±æ§
4.æ¶æ¯è½¬å(çæ´æ°)解å³Bug(JSPatch)
ios ä¸runtimeårunloop çåºå«
ä¸.RunLoop:Runloopæ¯äºä»¶æ¥æ¶åååæºå¶çä¸ä¸ªå®ç°ã
Runloopæä¾äºä¸ç§å¼æ¥æ§è¡ä»£ç çæºå¶ï¼ä¸è½å¹¶è¡æ§è¡ä»»å¡ã
å¨ä¸»éåä¸ï¼Main RunLoopç´æ¥é åä»»å¡çæ§è¡ï¼è´è´£å¤çUIäºä»¶ãå®æ¶å¨ä»¥åå ¶ä»å æ ¸ç¸å ³äºä»¶ã
(1).RunLoopç主è¦ç®çï¼
ä¿è¯ç¨åºæ§è¡ç线ç¨ä¸ä¼è¢«ç³»ç»ç»æ¢ã
(2).ä»ä¹æ¶å使ç¨Runloop ï¼
å½éè¦å该线ç¨è¿è¡äº¤äºçæ¶åæä¼ä½¿ç¨Runloop.
æ¯ä¸ä¸ªçº¿ç¨é½æå ¶å¯¹åºçRunLoopï¼ä½æ¯é»è®¤é主线ç¨çRunLoopæ¯æ²¡æè¿è¡çï¼éè¦ä¸ºRunLoopæ·»å è³å°ä¸ä¸ªäºä»¶æºï¼ç¶åå»runå®ã
ä¸è¬æ åµä¸æ们æ¯æ²¡æå¿ è¦å»å¯ç¨çº¿ç¨çRunLoopçï¼é¤éä½ å¨ä¸ä¸ªåç¬ç线ç¨ä¸éè¦é¿ä¹ çæ£æµæ个äºä»¶ã
主线ç¨é»è®¤æRunloopãå½èªå·±å¯å¨ä¸ä¸ªçº¿ç¨ï¼å¦æåªæ¯ç¨äºå¤çåä¸çäºä»¶ï¼å该线ç¨å¨æ§è¡å®ä¹åå°±éåºäºãæ以å½æ们éè¦è®©è¯¥çº¿ç¨çå¬æ项äºå¡
æ¶ï¼å°±å¾è®©çº¿ç¨ä¸ç´ä¸éåºï¼runloopå°±æ¯è¿ä¹ä¸ä¸ªå¾ªç¯ï¼æ²¡æäºä»¶çæ¶åï¼ä¸ç´å¡çï¼æäºä»¶æ¥ä¸´äºï¼æ§è¡å ¶å¯¹åºçå½æ°ã
RunLoop,æ£å¦å ¶åæ示,æ¯çº¿ç¨è¿å ¥å被线ç¨ç¨æ¥ç¸åºäºä»¶ä»¥åè°ç¨äºä»¶å¤çå½æ°çå°æ¹.éè¦å¨ä»£ç ä¸ä½¿ç¨æ§å¶è¯å¥å®ç°RunLoopç循ç¯,ä¹å°±æ¯è¯´,éè¦ä»£ç æä¾whileæè for循ç¯æ¥é©±å¨RunLoop.
å¨è¿ä¸ªå¾ªç¯ä¸,使ç¨ä¸ä¸ªrunLoop对象[NSRunloop currentRunloop]æ§è¡æ¥æ¶æ¶æ¯,è°ç¨å¯¹åºçå¤çå½æ°.
Runloopæ¥æ¶ä¸¤ç§æºäºä»¶:input sourcesåtimer sourcesã
input sources ä¼ éå¼æ¥äºä»¶ï¼é常æ¯æ¥èªå ¶ä»çº¿ç¨åä¸åçç¨åºä¸çæ¶æ¯ï¼
timer sources(å®æ¶å¨) ä¼ éåæ¥äºä»¶ï¼éå¤æ§è¡æè å¨ç¹å®æ¶é´ä¸è§¦åï¼ã
é¤äºå¤çinput sourcesï¼Runloop
ä¹ä¼äº§çä¸äºå ³äºæ¬èº«è¡ä¸ºçnotificaitonã注åæ为Runloopçobserverï¼å¯ä»¥æ¥æ¶å°è¿äºnotificationï¼åä¸äºé¢å¤
çå¤çãï¼ä½¿ç¨CoreFoundationæ¥æ为runloopçobserverï¼ã
Runloopå·¥ä½çç¹ç¹:
1>å½ææ¶é´åçæ¶,Runloopä¼æ ¹æ®å ·ä½çäºä»¶ç±»åéç¥åºç¨ç¨åºä½åºç¸åº;
2>å½æ²¡æäºä»¶åçæ¶,Runloopä¼è¿å ¥ä¼ç ç¶æ,ä»èè¾¾å°ççµçç®ç;
3>å½äºä»¶å次åçæ¶,Runloopä¼è¢«éæ°å¤é,å¤çäºä»¶.
æ示:ä¸è¬å¨å¼åä¸å¾å°ä¼ä¸»å¨å建Runloop,èé常ä¼æäºä»¶æ·»å å°Runloopä¸.
äº.Runtime:
RunTimeç®ç§°è¿è¡æ¶ãå°±æ¯ç³»ç»å¨è¿è¡çæ¶åçä¸äºæºå¶ï¼å ¶ä¸æ主è¦çæ¯æ¶æ¯æºå¶ã对äºCè¯è¨ï¼å½æ°çè°ç¨å¨ç¼è¯çæ¶åä¼å³å®è°ç¨åªä¸ªå½æ°ï¼
Cè¯è¨çå½æ°è°ç¨è¯·çè¿é
ï¼ãç¼è¯å®æä¹åç´æ¥é¡ºåºæ§è¡ï¼æ ä»»ä½äºä¹æ§ãOCçå½æ°è°ç¨æ为æ¶æ¯åéãå±äºå¨æè°ç¨è¿ç¨ãå¨ç¼è¯çæ¶å并ä¸è½å³å®çæ£è°ç¨åªä¸ªå½æ°ï¼äºå®è¯æï¼å¨ç¼
è¯é¶æ®µï¼OCå¯ä»¥è°ç¨ä»»ä½å½æ°ï¼å³ä½¿è¿ä¸ªå½æ°å¹¶æªå®ç°ï¼åªè¦ç³æè¿å°±ä¸ä¼æ¥éãèCè¯è¨å¨ç¼è¯é¶æ®µå°±ä¼æ¥éï¼ãåªæå¨çæ£è¿è¡çæ¶åæä¼æ ¹æ®å½æ°çå称æ¾
å°å¯¹åºçå½æ°æ¥è°ç¨ã
é£OCæ¯æä¹å®ç°å¨æè°ç¨çå¢ï¼ä¸é¢æ们æ¥ççOCéè¿åéæ¶æ¯æ¥è¾¾å°å¨æè°ç¨çç§å¯ãåå¦å¨OCä¸åäºè¿æ ·çä¸ä¸ªä»£ç ï¼
[objc] view plain?
<span style="font-size:px;">[obj makeText];</span>
å ¶ä¸objæ¯ä¸ä¸ªå¯¹è±¡ï¼makeTextæ¯ä¸ä¸ªå½æ°å称ã对äºè¿æ ·ä¸ä¸ªç®åçè°ç¨ãå¨ç¼è¯æ¶RunTimeä¼å°ä¸è¿°ä»£ç 转åæ
[objc] view plain?
objc_msgSend(obj,@selector(makeText));
é¦å æ们æ¥ççobjè¿ä¸ªå¯¹è±¡ï¼iOSä¸çobjé½ç»§æ¿äºNSObjectã
[objc] view plain?
@interface NSObject <nsobject> {
Class isa OBJC_ISA_AVAILABILITY;
}</nsobject>
å¨NSObjcetä¸åå¨ä¸ä¸ªClassçisaæéãç¶åæ们ççClassï¼
[objc] view plain?
typedef struct objc_class *Class;
struct objc_class {
Class isa; // æåmetaclass
Class super_class ; // æåå ¶ç¶ç±»
const charchar *name ; // ç±»å
long version ; // ç±»ççæ¬ä¿¡æ¯ï¼åå§åé»è®¤ä¸º0ï¼å¯ä»¥éè¿runtimeå½æ°class_setVersionåclass_getVersionè¿è¡ä¿®æ¹ã读å
long info; // ä¸äºæ è¯ä¿¡æ¯,å¦CLS_CLASS (0x1L) 表示该类为æ®é class ï¼å ¶ä¸å å«å¯¹è±¡æ¹æ³åæååé;CLS_META (0x2L) 表示该类为 metaclassï¼å ¶ä¸å å«ç±»æ¹æ³;
long instance_size ; // 该类çå®ä¾åé大å°(å æ¬ä»ç¶ç±»ç»§æ¿ä¸æ¥çå®ä¾åé);
struct objc_ivar_list *ivars; // ç¨äºåå¨æ¯ä¸ªæååéçå°å
struct objc_method_list **methodLists ; // ä¸ info çä¸äºæ å¿ä½æå ³,å¦CLS_CLASS (0x1L),ååå¨å¯¹è±¡æ¹æ³ï¼å¦CLS_META (0x2L)ï¼ååå¨ç±»æ¹æ³;
struct objc_cache *cache; // æåæè¿ä½¿ç¨çæ¹æ³çæéï¼ç¨äºæåæçï¼
struct objc_protocol_list *protocols; // åå¨è¯¥ç±»éµå®çåè®®
}
æ们å¯ä»¥çå°ï¼å¯¹äºä¸ä¸ªClassç±»ä¸ï¼åå¨å¾å¤ä¸è¥¿ï¼ä¸é¢ææ¥ä¸ä¸è§£éä¸ä¸ï¼
Class
isaï¼æåmetaclassï¼ä¹å°±æ¯éæçClassãä¸è¬ä¸ä¸ªObj对象ä¸çisaä¼æåæ®éçClassï¼è¿ä¸ªClassä¸åå¨æ®éæååéå对
象æ¹æ³ï¼â-âå¼å¤´çæ¹æ³ï¼ï¼æ®éClassä¸çisaæéæåéæClassï¼éæClassä¸åå¨staticç±»åæååéåç±»æ¹æ³ï¼â+âå¼å¤´çæ¹
æ³ï¼ã
Class super_class:æåç¶ç±»ï¼å¦æè¿ä¸ªç±»æ¯æ ¹ç±»ï¼å为NULLã
ä¸é¢ä¸å¼ å¾çå¾å¥½çæè¿°äºç±»å对象ç继æ¿å ³ç³»ï¼
注æï¼ææmetaclassä¸isaæéé½æåè·metaclassãèè·metaclassåæåèªèº«ã
Root metaclassæ¯éè¿ç»§æ¿Root class产ççãä¸root classç»æä½æåä¸è´ï¼ä¹å°±æ¯åé¢æå°çç»æãä¸åçæ¯Root
metaclassçisaæéæåèªèº«ã
Classç±»ä¸å ¶ä»çæåè¿éå°±å ä¸åè¿å¤è§£éäºï¼ä¸é¢æ们æ¥ççï¼
@selector (makeText)ï¼
è¿æ¯ä¸ä¸ªSELæ¹æ³éæ©å¨ãSELå ¶ä¸»è¦ä½ç¨æ¯å¿«éçéè¿æ¹æ³ååï¼makeTextï¼æ¥æ¾å°å¯¹åºæ¹æ³çå½æ°æéï¼ç¶åè°ç¨å ¶å½æ°ãSELå ¶æ¬èº«æ¯ä¸ä¸ª
Intç±»åçä¸ä¸ªå°åï¼å°åä¸åæ¾çæ¹æ³çååã对äºä¸ä¸ªç±»ä¸ãæ¯ä¸ä¸ªæ¹æ³å¯¹åºçä¸ä¸ªSELãæ以iOSç±»ä¸ä¸è½åå¨2个å称ç¸åçæ¹æ³ï¼å³ä½¿åæ°ç±»åä¸
åï¼å 为SELæ¯æ ¹æ®æ¹æ³ååçæçï¼ç¸åçæ¹æ³å称åªè½å¯¹åºä¸ä¸ªSELã
ä¸é¢æ们就æ¥ççå ·ä½æ¶æ¯åéä¹åæ¯æä¹æ¥å¨ææ¥æ¾å¯¹åºçæ¹æ³çã
é¦å ï¼ç¼è¯å¨å°ä»£ç [obj makeText];转å为objc_msgSend(obj, @selector
(makeText));ï¼å¨objc_msgSendå½æ°ä¸ãé¦å éè¿objçisaæéæ¾å°obj对åºçclassãå¨Classä¸å å»cacheä¸
éè¿SELæ¥æ¾å¯¹åºå½æ°methodï¼çæµcacheä¸methodå表æ¯ä»¥SEL为keyéè¿hash表æ¥åå¨çï¼è¿æ ·è½æé«å½æ°æ¥æ¾é度ï¼ï¼è¥
cacheä¸æªæ¾å°ãåå»methodListä¸æ¥æ¾ï¼è¥methodlistä¸æªæ¾å°ï¼ååsuperClassä¸æ¥æ¾ãè¥è½æ¾å°ï¼åå°methodå
å ¥å°cacheä¸ï¼ä»¥æ¹ä¾¿ä¸æ¬¡æ¥æ¾ï¼å¹¶éè¿methodä¸çå½æ°æé跳转å°å¯¹åºçå½æ°ä¸å»æ§è¡ã
2024-11-30 12:17
2024-11-30 12:06
2024-11-30 11:00
2024-11-30 10:47
2024-11-30 10:12