runtimeintroduce

Runtime is called runtime. It is a dynamic phase, different from compile-time, when the code runs and is loaded into memory. If something goes wrong, the program will crash.

Compilation is the process of translating source code into code that can be recognized by the machine. It is mainly the most basic check of the language to report errors, that is, lexical analysis, grammar analysis and so on. It is a static stage.

forward

Method calls in OC are essentially sending messages (objc_msgSend)

Flow chart of message forwarding

One, message search
  • Quick lookup: by looking in the method cacheIMP
  • Slow search according to source codelookUpImpOrForwardMethods to analyze
Reasonableclasscount ();) {/ / lookup cache to see if there is the method the if (curClass - > cache. IsConstantOptimizedCache strict (/ * * / true)) {# if CONFIG_USE_PREOPT_CACHES imp = cache_getImp(curClass, sel); if (imp) goto done_unlock; curClass = curClass->cache.preoptFallbackClass(); Method meth = getMethodNoSuper_nolock(curClass, sel); if (meth) { imp = meth->imp(false); goto done; If (slowPath ((curClass = curClass->getSuperclass()) == nil)) {// No implementation found, and method resolver didn't help. // Use forwarding. imp = forward_imp; break; } } // Halt if there is a cycle in the superclass chain. if (slowpath(--attempts == 0)) { _objc_fatal("Memory corruption  in class list."); Imp = cache_getImp(curClass, sel); if (slowpath(imp == forward_imp)) { // Found a forward:: entry in a superclass. // Stop searching, but don't cache yet; call method // resolver for this class first. break; } if (fastpath(imp)) { // Found the method in a superclass. Cache it in this class. goto done; If (slowpath(behavior & LOOKUP_RESOLVER)) {// implement found. behavior ^= LOOKUP_RESOLVER; return resolveMethod_locked(inst, sel, cls, behavior); } done: if (fastpath((behavior & LOOKUP_NOCACHE) == 0)) { #if CONFIG_USE_PREOPT_CACHES while (cls->cache.isConstantOptimizedCache(/* strict */true)) { cls = cls->cache.preoptFallbackClass(); } log_and_fill_cache(CLS, imp, sel, inst, curClass); } done_unlock: runtimeLock.unlock(); if (slowpath((behavior & LOOKUP_NIL) && imp == forward_imp)) { return nil; } return imp;Copy the code

2. Check whether getMethodNoSuper_nolock finds IMP in the current class. GetMethodNoSuper_nolock – > search_method_list_inline – > findMethodInSortedMethodList – > findMethodInSortedMethodList. FindMethodInSortedMethodList source code analysis

template<class getNameFunc> ALWAYS_INLINE static method_t * findMethodInSortedMethodList(SEL key, const method_list_t *list, const getNameFunc &getName) { ASSERT(list); auto first = list->begin(); auto base = first; decltype(first) probe; uintptr_t keyValue = (uintptr_t)key; uint32_t count; for (count = list->count; count ! = 0; Probe = base + (count >> 1); uintptr_t probeValue = (uintptr_t)getName(probe); // If it is equal, While (probe > first && keyValue == (uintptr_t)getName((probe-1)) { probe--; } return &*probe; If (keyValue > probeValue) {base = probe + 1; if (keyValue > probeValue) {base = probe + 1; count--; } } return nil; }Copy the code
  • If a method is found in the current classIMP, then jump done:Method to cache the current methodlog_and_fill_cacheWill execute the codecls->cache.insert(sel, imp, receiver);Caching methods.
static void log_and_fill_cache(Class cls, IMP imp, SEL sel, id receiver, Class implementer) { #if SUPPORT_MESSAGE_LOGGING if (slowpath(objcMsgLogEnabled && implementer)) { bool cacheIt = logMessageSend(implementer->isMetaClass(), cls->nameForLogging(), implementer->nameForLogging(), sel); if (! cacheIt) return; } #endif cls->cache.insert(sel, imp, receiver); }Copy the code
  • If the current class is not found, go to the parent classlookUpImpOrForwardLookup, which is executed when the method is not foundresolveMethod_lockedmethodsDynamic method resolution
Dynamic method resolution

When this method is not present in either the class or metaclass, the OC gives the opportunity to handle dynamic method resolution in order to prevent flashbacks

  • Fast forward When slow lookup, resolution and dynamic methods were not find implementation, for message forwarding, the first is a quick message forwarding, namely forwardingTargetForSelector method

    1. If the message receiver is returned and still not found in the message receiver, enter the search process of another method

    2. If nil is returned, slow message forwarding enters

  • Slow forwarded to methodSignatureForSelector method

    1. If a method is returned with a nil signature, it crashes

    2. If the returned method is not signed nil, go to the forwardInvocation method and the invocation transaction is handled without an error

ResolveMethod_locked source code parsing

static NEVER_INLINE IMP resolveMethod_locked(id inst, SEL sel, Class cls, int behavior) { runtimeLock.assertLocked(); ASSERT(cls->isRealized()); runtimeLock.unlock(); // give a chance to handle IMP if (! CLS - > isMetaClass ()) {/ / / / object method try/CLS resolveInstanceMethod: sel resolveInstanceMethod (inst, sel, CLS); } else {/ / try [nonMetaClass resolveClassMethod: sel] / / and/CLS resolveInstanceMethod: sel / / class methods resolveClassMethod(inst, sel, cls); if (! LookUpImpOrNilTryCache (inst, sel, CLS) {// Because class methods are instance methods in metaclass, Therefore, we need to find the dynamic method resolution resolveInstanceMethod(INST, SEL, CLS) of the instance method in the metaclass. } } // chances are that calling the resolver have populated the cache // so attempt using it return lookUpImpOrForwardTryCache(inst, sel, cls, behavior); }Copy the code
/ / 1: Fast forward - (id) forwardingTargetForSelector: (SEL) aSelector {NSLog (@ - % @ "% s", __func__, NSStringFromSelector (aSelector)); // runtime + aSelector + addMethod + imp return [super forwardingTargetForSelector:aSelector]; } / / 2: Slow forward - (NSMethodSignature *) methodSignatureForSelector: (SEL) aSelector {NSLog (@ % s -. %@",__func__,NSStringFromSelector(aSelector)); return nil; } - (void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"%s - %@",__func__,anInvocation); anInvocation.target = [JCStudent alloc]; // Invocation invocation - Method [anInvocation invocation]; }Copy the code