“This is the 12th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

preface

I believe that in normal development, there will also be some runtime applications, like my original article “iOS quick summary” is the application of the Runtime dynamic access to the class attribute name to achieve, of course, the level is still some times, runtime extensive and in-depth I am not even a steplingstone estimate. Here can only list some commonly used things, there may be some students do not particularly understand, can be a note to understand it

Interpretation of the

Common scenario

Get member variables dynamically

Dynamic access member variables This way the function of the most iconic is model dictionary earn, believe that everyone in the project this is also a necessary option, so the runtime does not say so mysterious, after all, you are using it every day, is simply a dynamic access to members of the class variables, then obtain corresponding to the name of the data from the dictionary, Assign to a member variable with the same name. Something like that

#import "NSObject+Ex.h" #import <objc/runtime.h> #import <objc/message.h> @implementation NSObject (Ex) + (instancetype)_initWithDictionaryForModel:(NSDictionary *)dic { id myObj = [[self alloc] init]; unsigned int outCount; Objc_property_t *arrPropertys = class_copyPropertyList([self class], &outCount); for (NSInteger i = 0; i < outCount; I ++) {// Get property name string objc_property_t property = arrPropertys[I]; / / model of the property name nsstrings * propertyName = [nsstrings stringWithUTF8String: property_getName (property)]; id propertyValue = dic[propertyName]; If ([propertyName isEqualToString:@"age3"]) {propertyValue = dic[@"age"]; } if (propertyValue ! = nil) { [myObj setValue:propertyValue forKey:propertyName]; }} // When the Runtime gets the property, it is not ARC Objective-C objects that need to release free(arrPropertys); return myObj; } @endCopy the code

Dynamically modify member variables

This method is most commonly used to retrieve private member variables. Because these variables are not published and cannot be modified directly, the runtime can retrieve these variables dynamically, and then modify the data in them. For example, in UITextField, We often change the color of the placeholder text, and this property is private

#import "UITextField+Ex.h" #import <objc/runtime.h> @implementation UITextField (Ex) - (void) changePlaceHolderTextColor: UIColor *) color {/ / this is to print out all member variables, for the member variable name unsigned int count; Ivar *ivars = class_copyIvarList([UITextField class], &count); for (int i = 0; i < count; Ivar = ivars[I]; Ivar = ivars[I]; // NSLog(@" member variable %s", ivar_getName(ivar)); } free(ivars); // iOS 13 uses KVC to modify private attributes. Not all KVC can Crash, try! If ([[UIDevice currentDevice].SystemVersion floatValue] > 13.0) {// Get a member variable, Ivar Ivar = class_getInstanceVariable([UITextField class], "_placeholderLabel"); UILabel *placeholderLabel = object_getIvar(self, ivar); placeholderLabel.textColor = color; } else {/ / KVC assignment, just use KVC assignment before iOS13 oh [self setValue: color forKeyPath: @ "_placeholderLabel. TextColor"]. } } @endCopy the code

Add attributes to categories

The application scenario of adding attributes to classification is to add functions to some system classes. For example, when I need to click this button again, I want to add a message data to this button, but the button of the system does not support it, and it is troublesome to write a button by myself. You can then dynamically add a property to the button to bind the message data

//.h file #import <Foundation/ foundation.h > @interface NSObject (Ex) @property (nonatomic, copy) NSString * MSG; #import <objc/runtime.h> @implementation NSObject (Ex) - (void)setMsg:(id) MSG { // Notice the type of the last argument objc_setMsg(self, @selector(MSG), associatedObject, OBJC_ASSOCIATION_COPY); } - (id)msg { return objc_getMsg(self, _cmd); } @endCopy the code

Methods exchange

The most common way to exchange methods is non-intrusive buried points. I believe that in many buried points, there will be more or less a part of the runtime shadow. There is also a kind of error handling, for example, if you want to add a nILL data to the array, it will crash normally, but before adding data, We can do a check, and only add data if it’s not nil, otherwise we don’t add it, and we’ll avoid the user experience

#import "NSMutableArray+ ex.h "#import <objc/runtime.h> + (void)load. + (void)load. */ + (void)load {static dispatch_once_t onceToken; / / static dispatch_once_t onceToken; Dispatch_once (&oncetoken, ^{ Class CLS = NSClassFromString(@"__NSArrayM"); Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:)); Method method2 = class_getInstanceMethod(cls, @selector(jf_insertObject:atIndex:)); method_exchangeImplementations(method1, method2); }); } - (void)jf_insertObject (id)anObject atIndex (NSUInteger)index {// If (anObject == nil) return; // If you do not know the underlying implementation logic, you can make all kinds of unexpected errors when implementing the system method. Method to implement the already swapped [self jf_insertObject:anObject atIndex:index]; } @endCopy the code

conclusion

The above statement about runtime is just the tip of the iceberg, there are many great gods who have made great things, if you have any questions or comments about what I have written, please let me know thank you