Good articles to my personal technology blog: https://cainluo.github.io/15033286127687.html


RunTime is a feature of Objective-C, in other words, because Objective-C is a dynamic language, and RunTime is its RunTime mechanism and so on and so forth, and so on and so forth…

But for scum like me, I think it’s just a bunch of STUFF written in C, so cut the crap and just masturbate.

Reprint statement: if you need to reprint this article, please contact the author, and indicate the source, and can not modify this article without authorization.


objc_msgSend

In our ordinary use, we will often declare a function, and then to call, but we do not know what operation, now let’s look at a piece of code:

#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
Copy the code

This code, which is normal Objective-C code that we write, can be rewritten from the terminal command line:

clang -rewrite-objc RunTimeModel.m
Copy the code

Then we get a runtimemodel. CPP file with 90,000 + lines of code in it, where we need to find something:

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(a))void *)objc_msgSend)((id)self, sel_registerName("sendMessage:"), (NSInteger)100);
    }

    return self;
}
Copy the code
((void(*) (id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("sendMessage"));

((void(*) (id, SEL, NSInteger(a))void *)objc_msgSend)((id)self, sel_registerName("sendMessage:"), (NSInteger)100);
Copy the code

This is what we do when we call a method in a.m file, which is converted to send messages to communicate. Objc_msgSend is declared in the #import

file:

OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... * / )
    OBJC_AVAILABLE(10.0.2.0.9.0.1.0);
Copy the code

There are two basic parameters, id and SEL respectively.


id / SEL

Id and SEL are both defined in #include

:

typedef struct objc_object *id;

typedef struct objc_selector *SEL;
Copy the code
  • SEL:Essentially a mapping to a methodCString, we can useObjective-Cthe@selector()orRunTimeIn thesel_registerNameTo get aSELType method selector.
  • id:It is a structure pointer type that can point toObjective-CAny object in.

Objc_object definition:

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};
Copy the code

In fact, this is the object’s original appearance, do not give beautiful appearance to deceive.

Isa isa member variable of a Class. It isa member variable of a Class. Isa isa member variable of a Class.


Class

#include

typedef struct objc_class *Class;
Copy the code

But actually Class is defined in #include

:

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;
Copy the code

Here’s what’s inside:

  • Class:There is also aisaPointer, pointing to the owningmeta(class).
  • Super_class: refers to its superclass.
  • Name: name of the class.
  • Version: indicates the version information of a class.
  • Info: details about a class.
  • Instance_size: The size of the sample object for this class.
  • Ivars: A list of member variables pointing to this class, including internal variables.
  • MethodLists: A list of sample methods pointing to this class, which links the method selector to the method implementation address.
  • cache: RuntimeWill save the called method tocacheWhen the method is called the first time, it is cached for the possibility that it will be called again.
  • Protocols: List of protocols pointing to this class.

Here,methodListsAnd notice, it’s pointing toobjc_method_listA pointer to a pointer, that is, it can be changed dynamicallymethodListsValue to add member methods, which we often useCategoryThat’s what it is, and because of it,CategoryThere’s usually no way to add attributes, so we have to write them ourselves.

See here, we almost know the basic things, now add a repair knife, look at the whole process:

  • RuntimeIt’s gonna get usThe method callintoMessage is sentThat’s what we were talking aboutobjc_msgSendAnd pass the method caller and method selector as arguments.
  • This is when the method caller passesisaPointer to find the class to which the method belongs, and thencacheormethodListsFind the called method and jump to the corresponding method to execute.
    • If the method is not found in the class, it passessuper_classLook up the superclass and execute if it finds it (what if it doesn’t? This will be added later).

Now, this may surprise some people, but methodLists are loaded with instance methods. What kind of methods?

Class methods are stored in a metaclass. The isa pointer is used to find the metaclass to which the Class belongs.

- (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); }}Copy the code

Printout results: Vim

The 2017-08-22 13:24:19. 455 (1) the RunTime [32885-2667202] _installAppearanceSwizzlesForSetter: The 13:24:19 2017-08-22. 456 (1) the RunTime [32885-2667202] __accessibilityGuidedAccessStateEnabled 2017-08-22 13:24:19. 456 1.RunTime[32885:2667202] __accessibilityGuidedAccessRestrictionStateForIdentifier: The 13:24:19 2017-08-22. 456 (1) the RunTime [32885-2667202] __accessibilityRequestGuidedAccessSession: completion: The 2017-08-22 13:24:19. 456 (1) the RunTime [32885-2667202] isSelectorExcludedFromWebScript: The 2017-08-22 13:24:19. 457 (1) the RunTime [32885-2667202] isKeyExcludedFromWebScript: [32885:2667202] _webkit_invokeOnMainThread 2017-08-22 13:24:19.457 1 1.RunTime[32885:2667202] sbs_dataFromObject: 2017-08-22 13:24:19.457 1.RunTime[32885:2667202] sbs_dataFromObject: 2017-08-22 13:24:19.457 The 2017-08-22 13:24:19. 458 (1) the RunTime [32885-2667202] sbs_dataWithValue: The 13:24:19 2017-08-22. 458 (1) the RunTime [32885-2667202] sbs_valueFromData: ofType: The 2017-08-22 13:24:19. 458 (1) the RunTime [32885-2667202] CA_automaticallyNotifiesObservers: The 2017-08-22 13:24:19. 459 (1) the RunTime [32885-2667202] CA_setterForProperty: The 2017-08-22 13:24:19. 459 (1) the RunTime [32885-2667202] CA_getterForProperty: The 2017-08-22 13:24:19. 459 (1) the RunTime [32885-2667202] CA_encodesPropertyConditionally:type1.RunTime[32885:2667202] CA_CAMLPropertyForKey: The 2017-08-22 13:24:19. 459 (1) the RunTime [32885-2667202] bs_decodedFromData: The 2017-08-22 13:24:19. 460 (1) the RunTime [32885-2667202] bs_objectFromData: The 13:24:19 2017-08-22. 460 (1) the RunTime [32885-2667202] bs_secureObjectFromData: ofClass: The 13:24:19 2017-08-22. 460 (1) the RunTime [32885-2667202] bs_secureObjectFromData: ofClasses: The 13:24:19 2017-08-22. 460 (1) the RunTime [32885-2667202] bs_synchronousWrapper: timeout: The 2017-08-22 13:24:19. 460 (1) the RunTime [32885-2667202] bs_secureDataFromObject: The 2017-08-22 13:24:19. 461 (1) the RunTime [32885-2667202] bs_dataFromObject: The 13:24:19 2017-08-22. 461 (1) the RunTime [32885-2667202] bs_secureDecodedFromData: withAdditionalClasses: The 2017-08-22 13:24:19. 461 (1) the RunTime [32885-2667202] bs_secureDecodedFromData: The 2017-08-22 13:24:19. 506 (1) the RunTime [32885-2667202] replacementObjectForPortCoder: The 2017-08-22 13:24:19. 506 (1) the RunTime [32885-2667202] instanceMethodDescriptionForSelector: The 2017-08-22 13:24:19. 507 (1) the 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: The 2017-08-22 13:24:19. 507 (1) the RunTime [32885-2667202] cancelPreviousPerformRequestsWithTarget: The 2017-08-22 13:24:19. 507 (1) the RunTime (32885-2667202)setRunTime[32885:2667202] implementsSelector: The 2017-08-22 13:24:19. 508 (1) the RunTime [32885-2667202] instancesImplementSelector: 2017-08-22 13:24:19.508 1.RunTime[32885:2667202] Load 2017-08-22 13:24:19.508 1 2017-08-22 13:24:19.509 1.RunTime[32885:2667202] classForKeyedUnarchiver 2017-08-22 13:24:19.509 1. The RunTime [32885-2667202] classFallbacksForKeyedArchiver 2017-08-22 13:24:19. 509 (1) the RunTime (32885-2667202) 13:24:19 _shouldAddObservationForwardersForKey: 2017-08-22. 509 (1) the RunTime (32885-2667202)setKeys:triggerChangeNotificationsForDependentKey: The 2017-08-22 13:24:19. 510 (1) the RunTime [32885-2667202] automaticallyNotifiesObserversForKey: The 2017-08-22 13:24:19. 510 (1) the RunTime [32885-2667202] _keysForValuesAffectingValueForKey: The 2017-08-22 13:24:19. 510 (1) the RunTime [32885-2667202] keyPathsForValuesAffectingValueForKey: The 13:24:19 2017-08-22. 510 (1) the RunTime [32885-2667202] _createValueGetterWithContainerClassID: key: The 13:24:19 2017-08-22. 511 (1) the RunTime [32885-2667202] _createValueSetterWithContainerClassID: key: The 13:24:19 2017-08-22. 511 (1) the RunTime [32885-2667202] _createMutableOrderedSetValueGetterWithContainerClassID: key: The 13:24:19 2017-08-22. 511 (1) the RunTime [32885-2667202] _createMutableSetValueGetterWithContainerClassID: key: The 13:24:19 2017-08-22. 511 (1) the RunTime [32885-2667202] _createValuePrimitiveGetterWithContainerClassID: key: The 13:24:19 2017-08-22. 512 (1) the RunTime [32885-2667202] _createValuePrimitiveSetterWithContainerClassID: key: The 13:24:19 2017-08-22. 512 (1) the RunTime [32885-2667202] _createOtherValueGetterWithContainerClassID: key: The 13:24:19 2017-08-22. 512 (1) the RunTime [32885-2667202] _createOtherValueSetterWithContainerClassID: key: The 13:24:19 2017-08-22. 512 (1) the RunTime [32885-2667202] _createMutableArrayValueGetterWithContainerClassID: key: The 13:24:19 2017-08-22. 513 (1) the 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 The 2017-08-22 13:24:19. 514 (1) the RunTime [32885-2667202] doesNotRecognizeSelector: 2017-08-22 13:24:19.514 1.RunTime[32885:2667202] description 2017-08-22 13:24:19.514 1. 13:24:19 methodSignatureForSelector: 2017-08-22. 514 (1) the 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. 13:24:19 instancesRespondToSelector: 2017-08-22. 516 (1) the RunTime [32885-2667202] instanceMethodForSelector: The 2017-08-22 13:24:19. 516 (1) the RunTime [32885-2667202] isAncestorOfObject: The 2017-08-22 13:24:19. 516 (1) the RunTime [32885-2667202] instanceMethodSignatureForSelector: 2017-08-22 13:24:19.516 1. Load 2017-08-22 13:24:19.517 1.RunTime[32885:2667202] Initialize The 2017-08-22 13:24:19. 517 (1) the RunTime [32885-2667202] resolveInstanceMethod: The 2017-08-22 13:24:19. 517 (1) the RunTime [32885-2667202] resolveClassMethod: Retain 2017-08-22 13:24:19.517 1.RunTime[32885:2667202] Retain 2017-08-22 13:24:19.518 1.RunTime[32885:2667202 2017-08-22 13:24:19.518 1.RunTime[32885:2667202] AutoRelease 2017-08-22 13:24:19.518 1.RunTime[32885:2667202] Taincount 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] Dealloc 2017-08-22 13:24:19.519 1 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] _retain 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] The 2017-08-22 13:24:19. 521 (1) the RunTime [32885-2667202] mutableCopyWithZone: The 2017-08-22 13:24:19. 522 (1) the 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 2017-08-22 13:24:19.522 1.RunTime[32885:2667202] mutableCopy 2017-08-22 13:24:19.523 1.RunTime[32885:2667202] 13:24:19 performSelector: withObject: 2017-08-22. 523 (1) the RunTime [32885-2667202] isMemberOfClass: The 2017-08-22 13:24:19. 524 (1) the RunTime (32885-2667202)hashThe 2017-08-22 13:24:19. 524 (1) the RunTime [32885-2667202] isEqual: 2017-08-22 13:24:19.524 1. Selector [32885:2667202] self 2017-08-22 13:24:19.524 1. Selector [32885:2667202] The 2017-08-22 13:24:19. 525 (1) the RunTime [32885-2667202] conformsToProtocol: The 2017-08-22 13:24:19. 525 (1) the RunTime [32885-2667202] methodSignatureForSelector: The 2017-08-22 13:24:19. 525 (1) the RunTime [32885-2667202] forwardingTargetForSelector: The 2017-08-22 13:24:19. 525 (1) the RunTime [32885-2667202] methodForSelector: The 2017-08-22 13:24:19. 526 (1) the 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 13:24:19.528 1.RunTime[32885:2667202] debugDescription 2017-08-22 13:24:19.528 1.RunTime[32885:2667202] isProxy The 2017-08-22 13:24:19. 529 (1) the RunTime [32885-2667202] respondsToSelector: The 2017-08-22 13:24:19. 529 (1) the RunTime [32885-2667202] isKindOfClass:Copy the code

Isa supplement

Here’s a sidebar to the isa pointer:

  • classtheisaThe pointer points to thetaThe metaclass.
  • The metaclasstheisaThe pointer points to thetaThe root class.
  • ifThe root classOr is itThe metaclassThe super class isNSObject“Then point to yourself.
  • NSObjectThere are no superclasses.


The project address

The address of the project: https://github.com/CainRun/iOS-Project-Example/tree/master/RunTime/ to play the iOS development: in the iOS RunTime (a)

Note:RunTimeModel.cppIn the catalog, I didn’t put it in the project.


The last