Summary of several key points of Objective C runtime Technology

Source: Internet
Author: User

Summary of several key points of Objective C runtime Technology

We recommend a good website www.joblai.com.

Preface:

Objective C's runtime technology is very powerful. It can obtain and modify various class information at runtime, including obtaining method lists, attribute lists, variable lists, modifying methods, attributes, and adding methods, attribute and so on. This article makes a summary of several key points.

Directory:

(1) Use the class_replaceMethod/class_addMethod function to dynamically Replace the function at runtime or add a new function.

(2) Reload forwardingTargetForSelector and forward unhandled selector to other objects.

(3) resolveInstanceMethod is reloaded to dynamically Add a selector when a selector cannot be processed.

(4) use class_copyPropertyList and property_getName to obtain the attribute list of the class and the name of each attribute.

(5) Use class_copyMethodList to obtain the list of all methods of the class.

(6) Summary

(1) dynamically Replace the function at runtime: class_replaceMethod

This function can be used to dynamically Replace the function implementation of a class at runtime. What is the purpose of this function? At the very least, you can achieve a hook effect similar to windows, that is, to intercept an instance function of the system class, and then add some of your own things, such as making a log or something.

Sample Code:

IMP orginIMP;NSString * MyUppercaseString(id SELF, SEL _cmd){    NSLog(@"begin uppercaseString");    NSString *str = orginIMP (SELF, _cmd);(3)    NSLog(@"end uppercaseString");    return str;}-(void)testReplaceMethod{      Class strcls = [NSString class];      SEL  oriUppercaseString = @selector(uppercaseString);      orginIMP = [NSStringinstanceMethodForSelector:oriUppercaseString];  (1)        IMP imp2 = class_replaceMethod(strcls,oriUppercaseString,(IMP)MyUppercaseString,NULL);(2)      NSString *s = "hello world";      NSLog(@"%@",[s uppercaseString]];}

The execution result is:

Begin uppercaseString

End uppercaseString

HELLO WORLD

The role of this Code is

(1) obtain the function pointer of the uppercaseString function and store it in the orginIMP variable.

(2) Replace the implementation of the uppercaseString function in the NSString class with the custom MyUppercaseString

(3) In MyUppercaseString, the log code is executed first, and then the system implementation of the previously saved uppercaseString is called, so that you can add your own items before the system function is executed, when you call uppercaseString for NSString, the log is printed.

Similar to class_replaceMethod, class_addMethod can add a function for the class at runtime.

(2) When an object cannot accept a selector, the call to the selector is forwarded to another object.:-(Id) forwardingTargetForSelector :( SEL) aSelector

ForwardingTargetForSelector is a NSObject function. You can overload it in a derived class and forward unhandled selector to another object. Take uppercaseString as an example. If the User-Defined CA Class Object a does not have an instance function such as uppercaseString, directly execute [a performSelector without calling respondSelector: @ selector "uppercaseString"], crash will be executed. At this time, if the CA implements the forwardingTargetForSelector function and returns an NSString object, then the uppercaseString function is executed relative to the NSString object, so no crash will be executed. Of course, the purpose of implementing this function is not only to make the program not as simple as crash, but also to use this function for message forwarding when implementing the modifier mode.

Sample Code:

 1 @interface CA : NSObject 3 -(void)f; 4  5 @end 6  7 @implementation CA 8  9 - (id)forwardingTargetForSelector:(SEL)aSelector11 {13     if (aSelector == @selector(uppercaseString))15     {17         return@"hello world";19     }21 }

Test code:

CA *a = [CA new]; NSString * s = [a performSelector:@selector(uppercaseString)];NSLog(@"%@",s);

The output of the test code is hello world.

Ps: there is a problem here. The CA Class Object cannot receive @ selector (uppercaseString). If I use class_addMethod IN THE forwardingTargetForSelector function to add an uppercaseString function to the CA class, and then return self, is it feasible? After testing, this will crash. At this time, the CA class actually already has the uppercaseString function, but I don't know why it cannot be called. If we create a new CA Class Object and return it, yes.

(3) When an object cannot accept a selector, dynamically Add the required selector to the class to which the object belongs.:

+ (BOOL) resolveInstanceMethod :( SEL) aSEL

This function is similar to forwardingTargetForSelector and will be triggered when the object cannot accept a selector. The execution is slightly different. The former aims to give the customer a chance to add the required selector to the object, and the latter aims to allow the user to forward the selector to another object. In addition, the trigger time is not exactly the same. This function is a class function. When the program is started and the interface is not displayed, it will be called.

If the class cannot process a selector, if the class reloads the function and adds the corresponding selector using class_addMethod, and returns YES, then forwardingTargetForSelector will not be called, if no corresponding selector is added to the function, no matter what is returned, the system will continue to call forwardingTargetForSelector. If no object can accept this selector is returned in forwardingTargetForSelector, the resolveInstanceMethod will be triggered again. If selector is not added, the program reports an exception.

1234567891011121314151617181920212223242526 Sample Code 1: 1@implementation CA 3void dynamicMethodIMP(id self,SEL _cmd) 5 { 7 printf("SEL %s did not exist\n",sel_getName(_cmd)); 9 }1011 + (BOOL) resolveInstanceMethod:(SEL)aSEL13 {15 if (aSEL == @selector(t))17 {19 class_addMethod([selfclass], aSEL, (IMP) dynamicMethodIMP, "v@:");21 return YES;23 }25 return [superresolveInstanceMethod:aSEL];27 }2829@end Test code: CA * ca = [CA new] [ca performSelector:@selector(t)];

  

Execution result

SEL t did not exist

123456789101112131415161718192021222324 Sample Code 2: @implementation CA void dynamicMethodIMP(id self,SEL _cmd){ printf("SEL %s did not exist\n",sel_getName(_cmd));} + (BOOL) resolveInstanceMethod:(SEL)aSEL{ return YES;}- (id)forwardingTargetForSelector:(SEL)aSelector{ if (aSelector == @selector(uppercaseString)) { return @"hello world"; }}Test code: a = [[CA alloc]init]; NSLog(@"%@",[a performSelector:@selector(uppercaseString)];

  

The output of the test code is hello world.

For this test code, because a does not have the uppercaseString function, the resolveInstanceMethod will be triggered. However, because this function does not add selector, it will be triggered if this function is not found during running.

The forwardingTargetForSelector function returns an NSString "hello world" in the forwardingTargetForSelector function. Therefore, the string executes the uppercaseString function and returns the uppercase hello world.

12345678910111213141516 Sample Code 3: @implementation CA + (BOOL) resolveInstanceMethod:(SEL)aSEL{ return YES;}- (id)forwardingTargetForSelector:(SEL)aSelector{ return nil; }Test code: 1 a = [[CA alloc]init];2 NSLog(@"%@",[a performSelector:@selector(uppercaseString)];

  

  

The execution sequence of this Code is:

(1): The resolveInstanceMethod is triggered when the program is just executed and the AppDelegate has not been released,

(2) When the test code is executed, forwardingTargetForSelector is called

(3) because forwardingTargetForSelector returns nil, The uppercaseString selector cannot be found during the runtime. In this case, the resolveInstanceMethod is triggered. Because the selector is not added, crash is triggered.

(4) use class_copyPropertyList and property_getName to obtain the attribute list of the class and the name of each attribute.

u_int count;objc_property_t* properties= class_copyPropertyList([UIView class], &count);for (int i = 0; i < count ; i++){ const char* propertyName = property_getName(properties[i]); NSString *strName = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; NSLog(@"%@",strName);}

The code above Retrieves all the attributes of UIView and prints the attribute name. The output result is:

skipsSubviewEnumerationviewTraversalMarkviewDelegatemonitorsSubtreebackgroundColorSystemColorNamegesturesEnableddeliversTouchesForGesturesToSuperviewuserInteractionEnabledtaglayer_boundsWidthVariable_boundsHeightVariable_minXVariable_minYVariable_internalConstraints_dependentConstraints_constraintsExceptingSubviewAutoresizingConstraints_shouldArchiveUIAppearanceTags

(5) Use class_copyMethodList to obtain the list of all methods of the class.

The obtained data is a Method array. The Method data structure contains information such as the function name, parameter, and return value. The following code obtains the name as an example:

u_int count;Method* methods= class_copyMethodList([UIView class], &count);for (int i = 0; i < count ; i++){ SEL name = method_getName(methods[i]); NSString *strName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding]; NSLog(@"%@",strName);}

After the code is executed, the names of all functions in UIView are output. The specific results are omitted.

Other related functions:

1. SEL method_getName (Method m) Get SEL2.IMP method_getImplementation (Method m) from Method get IMP function pointer 3. const char * method_getTypeEncoding (Method m) obtains type encoding information from Method 4. unsigned int method_getNumberOfArguments (Method m) to obtain the number of parameters 5. char * method_copyReturnType (Method m) Get the return value type name 6.IMP method_setImplementation (Method m, IMP imp) to set a new implementation for this Method

(6) Summary

In short, what can we do with the runtime technology?

You can perform many operations for various types (including System Classes) without inheriting or category at runtime, including:

  • Add
    Add function: class_addMethodAdd instance variable: class_addIvarAdd attributes:@dynamicLabel or class_addMethod, because the attribute is actually composed of the getter and setter functions.Add Protocol: class_addProtocol (to be honest, I really don't know how to add a protocol dynamically ,-_-!!)
    • Obtain
      Obtain the function list and information of each function (function pointer, function name, etc.): class_getClassMethod method_getName...Obtain the attribute list and information of each attribute: class_copyPropertyList property_getNameObtain information about the class, such as the class name: class_getName class_getInstanceSizeGet the Variable list and variable information: class_copyIvarListGet the variable value
      • Replace
        Replace the instance with another class: object_setClassReplace the function with a function implementation: class_replaceMethodDirectly passchar * The format name is used to modify the value of a variable instead of a variable.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.