first, what is Runtime (the so-called "runtime") because it is implemented at run time. )
1.runtime is a set of underlying C language API (including many powerful and practical C language types, C language functions); [Runtime operating system]
2. In fact, we write the OC code, the bottom layer is based on runtime implementation; [The dynamics of OC language]
  runtime system (runtime system), for C The language in which a function's call determines which function to call at compile time. For OC is a dynamic call procedure, at compile time does not decide which function to actually call, The corresponding function will be called based on the name of the function only when it is actually running. runtime is OC hard-working behind the scenes. (The compiler automatically helps us compile the runtime code. )
dynamic characteristics that enable it to support the extensibility of the program at the language level. The type of the object is determined only when the program is running, and the method corresponding to the object is called. the runtime mechanism allows us to dynamically modify the concrete implementation of the class, including all private properties and methods in the class, while the program is running. This is also the starting point of this sample runtime example.
the code we've typed is translated into Runtime Code of the runtime function, which eventually turns to the underlying runtime C when the program is running. Language code ;
Example:
When an object uses the syntax [receiver message] to invoke a method, [receiver message] is converted by the compiler to:
ID objc_msgsend (ID self, SEL op, ...);
Which means , We usually write the oc Code, the essence of the method call, is in the compilation phase, the compiler converted to Sends a message to an object.
" This development environment: xcode:7.2 IOS Simulator:iphone6 by: Ah left this article D emo Download Link: runtime-demo "
Second, the runtime of the use of several methods
We learn from the runtime by inheriting from the person class of nsobject.
This article contains a total of 6 examples of runtime mechanism methods, namely:
- Get All variables of the person class;
- Get All methods of the person class;
- Change The value of the private variable name of the person class;
- Add a new attribute to the category class for person;
- to be Add a method to the person class;
- Exchange The function of the 2 methods of the person class;
(personal habits, like to add buttons for 6 examples of their respective behavior, and perform the corresponding behavior, to see the specific functions of each runtime function of the effect.) )
First, create a new project and a new normal OC class in the project: The Person class ( inherited from NSObject), in order to avoid the subsequent mixing with other method functions, we have completed the complete person class, used in the following ways of using runtime:
①person.h as follows:
#import <Foundation/Foundation.h> @interface Person:nsobject
@property (nonatomic,assign) int age; Attribute variable-(void) func1;-(void) Func2; @end
②PERSON.M as follows:
#import "Person.h" @implementation person{ nsstring *name; Instance variable}//initializes the person property-(instancetype) init{self = [super init]; if (self) { name = @ "Tom"; Self.age = n; } return self;} The 2 common methods of Person-(void) func1{ NSLog (@) Execute the Func1 method. ");} -(void) func2{ NSLog (@) executes the Func2 method. ");} Method for outputting Person Object:-(NSString *) description{ return [nsstring stringwithformat:@ "name:%@ age:%d", Name,self.age] ;} @end
From the description of the person class, we can see that the person class contains a common attribute that can be used by the outer class, and that an outside world cannot access the private property name, but, there is wood to think about, in fact, outside the class, name can also be accessed. OC inside, through the runtime system, Apple allows to access, add, modify, and even replace the system without the restriction of these private attributes, such as private proprietary methods.
Then, add 6 buttons for the project storyboard;
In the case of runtime, we all need to include the header file: (in a few examples in this article, we just need to include it in VIEWCONTROLLER.M.)
#import <objc/runtime.h>
1. Get all the variables for the person class
Associate the first button to ViewController.h, add the behavior, and name its method: "getallvariable":
-(Ibaction) getallvariable: (UIButton *) sender; Get all variables
The implementation in VIEWCONTROLLER.M is as follows:
/*1. Gets all member variables of person */-(ibaction) getallvariable: (UIButton *) Sender {
unsigned int count = 0; Gets a list of all the variables in the class, Ivar is a macro declared by the runtime, which is the meaning of the instance variable. Ivar *allvariables = class_copyivarlist ([Person class], &count); for (int i = 0;i<count;i++) { //traverse each variable, including the name and type (there is no asterisk "*") Ivar Ivar = allvariables[i]; const char *variablename = Ivar_getname (Ivar); Gets the member variable name const char *variabletype = ivar_gettypeencoding (Ivar); Gets the member variable type NSLog (@ "(Name:%s)-----(type:%s)", Variablename,variabletype);} }
When you click on the button, the output is as follows: (i = type int)
analysis :Ivar, a pointer to the OBJC_IVAR structure, contains information such as variable name, variable type, and so on.
As you can see, the private property name can be accessed. In some projects, in order to hide some of the private properties, some. h files do not appear in the corresponding explicit creation, but as in the person class above, in. m for private creation, but we can through the runtime this effective method, access to all include these hidden private variables.
Expansion :
①class_copyivarlist is able to get a list of all the member variables in the class, including the attribute variables and the instance variables in the list. It is important to note that if, as in this example, age returns "_age", but if you join in PERSON.M:
@synthesize age;
Then the second line of the console returns "(name:age)-----(TYPE:I);" (Because @property is generating "_age" and @synthesize is executing "@synthesize age = _age , the specific knowledge about the difference between OC attribute variable and instance variable, @property, @synthesize, etc., interested children shoes can be understood by themselves. )
② if you simply need to get a list of attributes, you can use the function: Class_copypropertylist (); Just the property variable returned is only "age", and the name of the instance variable is not fetched.
The Class_copyivarlist () function can return all the member variables of the instance variable and the property variable.
2. Get all the methods of the person class
Associate the second button to ViewController.h, add the behavior, and name its method: "Getallmethod":
-(Ibaction) Getallmethod: (UIButton *) sender; Get all methods
The implementation in VIEWCONTROLLER.M is as follows:
/*2. Get all methods of person */-(ibaction) Getallmethod: (UIButton *) Sender {
unsigned int count;
Gets a list of methods that all explicitly implemented in. m files will be found, including the Setter+getter method *allmethods = class_copymethodlist ([Person class], & count); for (int i =0;i<count;i++) { //method, a macro declared for runtime, representing the description of a method MD = allmethods[i]; Gets the Sel:sel type, which is the Get method selector @selector () sel sel = method_getname (MD); Get the Sel method name: Gets the name of the SEL in string format, also known as the method names in @selector () const char *methodname = sel_getname (sel); NSLog (@ "(method:%s)", methodname); }}
After clicking the button, the console output:
2016-05-19 17:05:19.880 Runtime Runtime [14054:678124] (METHOD:FUNC1) 2016-05-19 17:05:19.881 Runtime Runtime [14,054:678,124] ( METHOD:FUNC2) 2016-05-19 17:05:19.881 Runtime Runtime [14054:678124] (method:setage:) 2016-05-19 17:05:19.881 Runtime Runtime [ 14054:678124] (method:age) 2016-05-19 17:05:19.881 Runtime Runtime [14054:678124] (method:.cxx_destruct) 2016-05-19 17:05:19.882 runtime Runtime [14054:678124] (method:description) 2016-05-19 17:05:19.882 Runtime Runtime [14054:678124] (Method: Init
The console outputs the name of the method including set and get. Note: the. Cxx_destruct method is a hidden function of the system's automatic memory release, which occurs when arc is present and the class has an instance variable.
Analysis :method is a pointer to a objc_method struct that represents a description of a method in a class. definitions in the API:
typedef struct Objc_method *method;
and objc_method结构体如下
:
Truct Objc_method { SEL method_name objc2_unavailable; Char *method_types objc2_unavailable; IMP method_imp objc2_unavailable;}
- Method_name:
方法选择器@selector(),类型为SEL
。
Under the same name method, even though they are defined in different classes, their method selectors are the same.
- Method_types: Method Type, which is a
char
pointer that stores the method's parameter type and return value type.
method_imp:指向
A pointer to the concrete implementation of the method, the data type of IMP, is essentially a function pointer. The fifth button behavior is mentioned in the "Add a Method" section.
SEL: A data type that represents a method selector, which can be understood as a wrapper over a method. in each method there is a corresponding SEL type of data, according to a SEL data "@selector (method Name)" can find the corresponding method address, and then call the method.
Therefore, it is possible to obtain the corresponding method name by obtaining the SEL selector name, which is obtained by means of method structure, so as to make it easy to understand the definition of methods in OC.
3. Change the value of the private variable name of the person class.
Associate the third button to ViewController.h, add the behavior, and name its method: "Changevariable":
-(Ibaction) changevariable: (UIButton *) sender;//Change the name variable
Create a Person object in viewcontroller.m, and remember to initialize
@implementation viewcontroller{person *per; Create a person instance}-(void) viewdidload { [super viewdidload]; per = [[Person alloc]init]; Remember to initialize ... Otherwise the consequences of their own try it out}
The implementation in VIEWCONTROLLER.M is as follows:
/*3. Change person's name variable property */-(ibaction) changevariable: (UIButton *) Sender {
NSLog (@ "person:%@ before change", per); unsigned int count = 0; Ivar *alllist = class_copyivarlist ([Person class], &count); Ivar IVV = alllist[0]; From the console information that is output from the first method getallvariable, we can see the name as the first instance property; Object_setivar (per, IVV, @ "Mike"); The Name property Tom is forced to change to Mike.
NSLog (@ "changed person:%@", per); }
After clicking the button, the console output:
2016-05-19 22:45:05.125 Runtime Runtime [1957:34,730] changes before Person:name:Tom age:122016-05-19 22:45:05.126 runtime runtime [1957:34,730] After the change of Person:name:Mike age:12
4. Add a new attribute to the category class for person:
How do I add a new property without changing a class?
A: You can use runtime to add a new attribute to a taxonomy.
In IOS , category is classified, it is not possible to add new attributes to this class, but in runtime we can use object affinity for person class to classify the new attribute creation:
① Create a new OC class:
Named:personcategory, click Next:
② in the new class "Person+personcategory.h" that appears, add "height":
#import "Person.h" @interface person (personcategory) @property (nonatomic,assign) float height; New Attribute @end
The code for the "PERSON+PERSONCATEGORY.M" class is as follows:
#import the use of the "Person+personcategory.h" #import <objc/runtime.h> //runtime API requires the const char * str = "MyKey" that contains this header file ; As key, the character constant must be a C language string; @implementation person (personcategory)-(void) SetHeight: (float) height{ nsnumber *num = [ NSNumber Numberwithfloat:height]; /* The first parameter is the object that needs to be added, and the second parameter is the key of the property; The third parameter is the value of the property, the type must be the ID, so the height is first converted to the NSNumber type, and the fourth parameter is the use policy, which is an enumeration value, similar to the keyword set when the @property attribute was created, which can be used to see the meaning of each enumeration; objc_setassociatedobject (self, str, num, objc_association_retain_nonatomic);} -(float) height{ //Extract the value of the attribute: nsnumber *number = objc_getassociatedobject (self, str); return [number Floatvalue];} @end
Next, we can access the height of an object of person in VIEWCONTROLLER.M,
Associate the fourth button to the ViewController.h add behavior and name its method: "AddVariable": (remember:#import "Person+personcategory.h")
-(Ibaction) AddVariable: (UIButton *) sender;
The implementation in VIEWCONTROLLER.M is as follows:
/* 4. Add a new attribute */-(ibaction) addvariable: (UIButton *) Sender { per.height = n; Assign a new property height assignment NSLog (@ "%f", [per height]);//Access new property value}
Click button Four, then click button One or two to get the properties, methods of the class.
2016-05-20 15:39:54.432 Runtime Runtime [4605:178974] 12.0000002016-05-20 15:39:56.295 Runtime runtime [4605:178974] (Name:name) -----(type:@ "NSString") 2016-05-20 15:39:56.296 Runtime Runtime [4605:178974] (Name: _age)-----(type:i) 2016-05-20 15:39:57.195 runtime Runtime [4605:178974] (METHOD:FUNC1) 2016-05-20 15:39:57.196 Runtime Runtime [4605:178974] (METHOD:FUNC2) 2016-05-20 15:39:57.196 Runtime Runtime [4605:178974] (method:setage:) 2016-05-20 15:39:57.196 Runtime Runtime [4,605:178,974] ( Method:age) 2016-05-20 15:39:57.196 Runtime Runtime [4605:178974] (method:.cxx_destruct) 2016-05-20 15:39:57.197 Runtime Runtime [4605:178974] (method:description) 2016-05-20 15:39:57.197 Runtime Runtime [4605:178974] (method:init) 2016-05-20 15:39:57.197 runtime Runtime [4605:178974] (method:height) 2016-05-20 15:39:57.197 Runtime Runtime [4605:178974] (Method: SetHeight:)
Analysis: You can see that new properties of the classification can be assigned to the new property height in the per object.
When you get to the person class property, there is still no height, but there are both the height and setheight methods, because in the classification, even if you use @property to define, you just generate the Set+get method without generating _ variable name. The definition of a variable is not allowed in the classification.
Using the Objc_setassociatedobject () and Objc_getassociatedobject () methods in runtime, essentially adding a property association to height for the object, but achieving the new property;
Usage scenario: Suppose Imagecategory is the classification of the UIImage class, in actual development, we use UIImage to download the image or the operation process needs to add a URL to save an address for later use. You can then try to add new attributes dynamically in the taxonomy Myurl for storage.
5. Add a new method for the person class;
Associate the fifth button to ViewController.h, add the behavior, and name its method: "Addmethod":
-(Ibaction) Addmethod: (UIButton *) sender;
The implementation in VIEWCONTROLLER.M is as follows:
/*5. Add a new method try (this method is equivalent to adding a category to the Father class to extend the method): */-(ibaction) Addmethod: (UIButton *) Sender {/ * Dynamic Add Method: The first parameter represents the class CLS type , the second parameter represents the method name to be called , and the third parameter (IMP) myaddingfunction,imp a function pointer, which indicates the specific implementation method myaddingfunction; Parameter of the fourth parameter table method, 0 for no parameters; * /Class_addmethod ([per class], @selector (newmethod), (IMP) Myaddingfunction, 0); Call method "If you invoke the method using [per Newmethod], the" No visible @interface "error is reported under Arc" [per Performselector: @selector (Newmethod )];} The specific implementation (the interior of the method contains two parameters class and Sel methods, which are called implicit parameters.) ) int myaddingfunction (ID self, SEL _cmd) { NSLog (@ "New method: Newmethod"); return 1;}
After clicking the button, the console output:
2016-05-20 14:08:55.822 Runtime [1957:34,730] New method added: Newmethod
6. The ability to exchange 2 methods of the person class:
Associate the sixth button to ViewController.h, add the behavior, and name its method: "Replacemethod":
-(Ibaction) Replacemethod: (UIButton *) sender;
The implementation in VIEWCONTROLLER.M is as follows:
/* 6. After swapping two methods (function Swap), you can try to make Apple mess ... */-(ibaction) Replacemethod: (UIButton *) Sender { Method method1 = Class_ Getinstancemethod ([Person class], @selector (func1)); Method method2 = Class_getinstancemethod ([Person class], @selector (FUNC2));
Exchange Method method_exchangeimplementations (method1, method2); [per func1]; After the output swap effect, you need to compare the func1 before you can try to run it under swap;}
After clicking the button, the console output:
2016-05-20 14:11:57.381 Runtime [1957:34,730] Executes the Func2 method.
Usage scenarios for Exchange methods: a feature in a project that needs to be referenced multiple times in a project, and when the requirements of a project change, a different function is used instead of the old project (i.e. without changing the original method implementation). then we can write a new method in the classification (which conforms to the new requirements) and then exchange the implementation of the two methods. In this way, without changing the code of the project, but only adding new code, the project has been improved, which is a good embodiment of the project's encapsulation and utilization.
Note: The implementation of the exchange two methods is generally written in the load method of the class, because the load method is loaded once before the program runs.
Several small examples of runtime (including demo)