IOS Runntime dynamically add class methods and Invoke-class_addmethod_ios

Source: Internet
Author: User
Tags instance method

After the development of IOS for some time, I found that not only focus on the completion of the requirements, the use of spare time to explore other development skills, in order to improve their level in a limited period. Of course, the proposition "Other development techniques" does not feel marginal to any development area, and for me, trying to touch Objc/runtime is the first step in exploring the development of IOS.

Just understand runtime of course to start with a relatively simple API, today to list and tidy up the relevant points of Class_addmethod:

Start with the document first.

/** * Adds A new method-a class with a given name and implementation. * * @param cl
S the class to which to add a method.
* @param name A selector that specifies, the name of the method being added. * @param imp A function which is the implementation's the new method.  The function must take at least two arguments-self and _cmd. * @param types A array of characters that describe the types 
Of the arguments to the method. * @return YES If the method is added successfully, otherwise NO * (for example, the class already contains a method I
Mplementation with that name). * * @note Class_addmethod would add an override of a superclass ' s implementation, * but won't be replace an existing imple 
Mentation in this class.
* To a existing implementation, use Method_setimplementation. * * Objc_export BOOL Class_addmethod (class cls, SEL name, IMP imp, const char *types) __osx_available_starting (__mac_10_5 
, __iphone_2_0); 

The effect of this method is to add a new method to the class and a concrete implementation of the method. Analyze the parameters required by this method:

Class CLS

The CLS parameter represents a class that needs to add a new method.

SEL Name

The name parameter represents the method name of the selector and can be named on its own liking.

IMP Imp

IMP is the implementation that represents a pointer to the implementation method generated by the compiler. That is, the method that the pointer points to is the method we want to add.

const CHAR *types

The last parameter, *types, represents the return value and parameters of the method that we want to add.

After briefly introducing the parameters and functions required in Class_addmethod, we can start using this method to add the methods we need. Before you use it, we first want to be clear objective-c as a dynamic language, it will put some of the code in the process of runtime execution, rather than compile, so in the execution of code, not only need a compiler, but also need a run-time environment (Runtime), in order to meet some requirements , Apple opened the Runtime source and provided an open API for developers to use.

Second, we need to know under what circumstances it is necessary to invoke the Class_addmethod method. When a project needs to inherit a class (subclass), but the parent class does not provide the calling method I need, and I do not know the exact implementation of some of the methods in the parent class, or I need to write a taxonomy for this class (category), in which I may need to replace/ Add a new method (note: It is not recommended to override the method in the classification, and it cannot be obtained by super to get the so-called parent class method). In both cases, we can achieve the desired effect through Class_addmethod.

Well, that's all. So how exactly should you call it? If you do not know how to use, then read the instructions is the best way. There are detailed usage methods in the documentation provided by Apple (Objective-c Runtime Programming Guide-dynamic Method Resolution), with the following Mycar This class describes the specific usage rules in detail:

First of all, since you want to add our method to a class, you should inherit or write a category to this class, where I'll create a new class called "mycar", as a category for the "car" class.

#import "Car+mycar.h"
@implementation car (mycar)
@end

We know that in objective-c, the normal invocation method is implemented through the message mechanism, so if the sent message method is not found in the class, the system goes into a process that cannot find the method, and if in this process we join the new method we need, will be able to implement the dynamic addition of the running process. This process, or mechanism, is OBJECTIVE-C's message forwarding

There are two main approaches involved in this mechanism:

+ (BOOL) Resolveinstancemethod: (SEL) SEL
+ (BOOL) Resolveclassmethod: (SEL) SEL

The only difference between the two methods is whether you want to add a static method or an instance method. Let's take the former, now that we're going to add the method, we'll implement it in the "mycar" class, and the code is as follows:

#import "Car+mycar.h"
void StartEngine (id self, SEL _cmd) {
NSLog (@ "My car starts the engine");
}
@implementation car (mycar)
@end

So far, we have implemented the StartEngine method that we are going to add. This is a C-language function that contains at least two arguments for self and _cmd (self represents the function itself, whereas _cmd is a SEL data body that contains a specific method address). What if you want to add a parameter to this method? See the following code:

#import "Car+mycar.h"
void StartEngine (id self, SEL _cmd, NSString *brand) {
NSLog (@ "My%@ car starts the engine" , brand);
}
@implementation car (mycar)
@end

As long as you add the required parameters and types after those two necessary parameters, the return value is the same, as long as the void before the method name is modified to the return type we want, we do not need to return the value here.

Next, we overload Resolveinstancemethod: this function:

#import "Car+mycar.h"
#import <objc/runtime.h>
void StartEngine (id self, SEL _cmd, NSString *brand) {
NSLog (@ "My%@ car starts the engine", brand);
}
@implementation car (Mycar)
+ (BOOL) Resolveinstancemethod: (SEL) sel {
if (sel = @selector (drive)) {
Class_ Addmethod ([Self class], SEL, (IMP) startengine, "v@:@");
Return YES
}
return [Super Resolveinstancemethod:sel];
}
@end

Explain that this function is executed in a runtime environment if the implementation of the method is not found. The first line determines whether the incoming SEL names match, then calls the Class_addmethod method and passes in the appropriate arguments. The third parameter passed in is the implementation of the C language function we added, that is, the name of the third parameter is the same as the specific function name added. The fourth parameter refers to the return value of the function and the contents of the parameter.

As for the return value of such a method, when I test it, no matter what the BOOL value is, it will not affect our execution target, and generally return YES.

If you feel that using the C language style to write a new function is not appropriate, then you can rewrite the following code:

@implementation car (Mycar)
+ (BOOL) Resolveinstancemethod: (SEL) sel {
if (sel = @selector (drive)) {
Class_ Addmethod ([Self class], SEL, class_getmethodimplementation (self, @selector (startengine:)), "s@:@");
Return YES
}
return [Super Resolveinstancemethod:sel];
}
-(void) StartEngine: (NSString *) Brand {
NSLog (@ "My%@ car starts the engine", brand);
}
@end

Where the class_getmethodimplementation meaning is to get the concrete implementation of the SEL pointer.

Then create a new class "dynamicselector", in which we implement the dynamic Add method to "car".

#import "DynamicSelector.h"
#import "Car+mycar.h"
@implementation dynamicselector
-(void) Dynamicaddmethod {car
*c = [[Car alloc] init];
[C Performselector: @selector (drive) withobject:@ "BMW"];
@end

Note that you cannot use [self method:] Here, because the method we add is executed at run time, and the compiler is only responsible for the compile-time method retrieval, and the error occurs once the drive method is not retrieved for an object, so here we use Performselector:withobject: To make calls, save, run.

2016-08-26 10:50:17.207 objc-runtime[76618:3031897] My BMW car starts the engine program
ended with exit code:0

The print results correspond to the goals we expect to achieve. If you need to return a value, the method is similar.

The above is a small set to introduce the iOS Runntime dynamic Add class method and call-class_addmethod, I hope to help you, if you have any questions please give me a message, small series will promptly reply to everyone. Here also thank you very much for the cloud Habitat Community website support!

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.