Basic use of the OBJECTIVE-C runtime (IOS Runtime's first experience)

Source: Internet
Author: User



First, runtime preface



The recent study of the runtime, the foundation is not good enough, research for a long time, only to understand some, know a probably, here to make a note. OC is a runtime language that determines the type of an object only when the program is running, and invokes the corresponding method of the object of the class. Using the runtime mechanism allows us to dynamically modify the class when the program is run, all properties in the object, methods, even private methods and private properties can be modified dynamically. So what I understand is the dynamic creation of classes, modification of classes, access to private methods and other basic features, it should be said to understand the basic usage of the runtime it!



Second, Runtime introduction



runtime abbreviation runtime, is the system at the time of operation of some mechanism, the most important is the message mechanism, runtime is a set of relatively low-level pure C language API, belongs to a C language library, we usually write the OC Code, the program in the process of running, In fact, eventually turned into the runtime of the C language code, runtime is OC's behind-the-scenes workers. such as OC: [[Person alloc] init]; Runtime:objc_msgsend (Objc_msgsden ("Peroson", "Allo"), "init") runtime is an open source library, where you can view the source code of the Apple website



Third, the runtime used in what scenario



1. Dynamically create a class during the program's run (for example, the underlying implementation of KVO)
2. Dynamically add properties \ Methods to a class, modify property values \ Methods during program run
3. Traverse all member variables (properties) of a class \ All methods
4. Exchange Method implementation
5. Dynamically Creating classes



Iv. terminology of the Runtime

We know [Person message]; Converted to objc_msgSend (Persong, @selelct (message)); It is like this
id obje_msgSend (id self, SEL op,…);

1.id
    The first parameter type id of objc_msgSend is a pointer to a class instance:
typedef struct objc_object * id (What is objc_object? See point 4)

2. The second parameter type SEL of SEL objc_msgSend function is the type of selector in Objc. selector is a method selector, which can be understood as the ID of the distinguishing method
3.… is a parameter

4.struct objc_object {Class isa;};
The objc_object structure contains an isa pointer, and the class to which the object belongs can be found based on the isa pointer. (You can view the source code)

4.Class
isa is a pointer because Class is actually a pointer to objc_class structure
typedef struct objc_class * Class
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;
This contains superclass pointers, class names, member variables, methods, caches, and attached protocols
Method: is a type that represents a method in the class
Ivar: is a type that represents instance variables in a class
IMP: This function pointer points to the implementation of this method
Cache: cache

related functions
objc_msgSend: send a message to the object
class_copyMethodList: traverse all methods of a class
class_copyIvarList: traverse all member variables of a class

Common sense 1> Ivar: member variable 2> Method: member method
V. Examples of Runtime scenarios

Each button corresponds to an operation
First create a Person class

Person.h file
//
// Person.h
// RuntimeTestDemo
//
// Created by GongHui_YJ on 16/6/2.
// Copyright? 2016 YangJian. All rights reserved.
//

#import <Foundation / Foundation.h>

@interface Person: NSObject

@property (strong, nonatomic) NSString * name;

@property (strong, nonatomic) NSString * address;

-(void) eat;

-(void) test1;

-(void) test2;

@end
Person.m file
//
// Person.m
// RuntimeTestDemo
//
// Created by GongHui_YJ on 16/6/2.
// Copyright? 2016 YangJian. All rights reserved.
//

#import "Person.h"

@implementation Person
{
    int age;
    NSString * sex;
}

-(instancetype) init
{
    self = [super init];
    if (self) {
        _name = @ "张三";
        _address = @ "Hangzhou City, Zhejiang Province";
        age = 18;
        sex = @ "男";
    }
    return self;
}

-(void) eat
{
    NSLog (@ "meal");
}

-(void) test1
{
    NSLog (@ "I am the test1 method");
}

-(void) test2
{
    NSLog (@ "I am the test2 method");
}

-(NSString *) description
{
    return [NSString stringWithFormat: @ "name:% @-age:% i-sex:% @-% @", _name, age, sex, _address];
}

@end
Implemented in ViewControll.m as follows

1. Get attribute \ member variable list Use class_copyIvaeList function
/ **
 * Get attributes / members
 *
 * @param sender sender
 * /
-(IBAction) getProperty: (id) sender {

    Class classPerson = NSClassFromString (@ "Person");
    NSLog (@ "-------------- Get the list of all member variables and print the results as follows -----------------");
    // Get the list of all member variables using class_copyIvarList
    unsigned int count = 0; //
    Ivar * ivarList = class_copyIvarList (classPerson, & count); // Get a list of all member variables count The number of record variables
    for (int i = 0; i <count; i ++) {
        Ivar ivar = ivarList [i]; // Take out the member variable of the i-th position
        const char * perosonName = ivar_getName (ivar); // Get variable name
        const char * perosonType = ivar_getTypeEncoding (ivar); // Get variable encoding type
        NSLog (@ "% s ----% s \ n", perosonName, perosonType);
    }

    NSLog (@ "-------------- Dividing line -----------------");
    NSLog (@ "-------------- Get all attribute list print result is as follows -----------------");
    // Get the property list using class_copyPropertyList
    unsigned int countProperty = 0;
    objc_property_t * propertyList = class_copyPropertyList (classPerson, & countProperty);
    for (int i = 0; i <countProperty; i ++) {
        const char * cName = property_getName (propertyList [i]);
        const char * butes = property_getAttributes (propertyList [i]);
        NSLog (@ "% s ---% s \ n", cName, butes);
    }


    // Get the printing result of member variable list (using class_copyIvarList function)
    / **
     2016-06-02 19: 26: 16.522 RuntimeTestDemo [32706: 3539390] -------------- Get the list of all member variables and print the results as follows ------------ -----
     2016-06-02 19: 26: 16.523 RuntimeTestDemo [32706: 3539390] age ---- i
     2016-06-02 19: 26: 16.523 RuntimeTestDemo [32706: 3539390] sex ---- @ "NSString"
     2016-06-02 19: 26: 16.523 RuntimeTestDemo [32706: 3539390] _name ---- @ "NSString"
     2016-06-02 19: 26: 16.523 RuntimeTestDemo [32706: 3539390] _address ---- @ "NSString"
     2016-06-02 19: 26: 16.524 RuntimeTestDemo [32706: 3539390] -------------- dividing line -----------------
     2016-06-02 19: 26: 16.524 RuntimeTestDemo [32706: 3539390] -------------- Get the list of all attribute print results are as follows ------------- ----
     2016-06-02 19: 26: 16.524 RuntimeTestDemo [32706: 3539390] name --- [email protected] "NSString", &, N, V_name
     2016-06-02 19: 26: 16.524 RuntimeTestDemo [32706: 3539390] address --- [email protected] "NSString", &, N, V_address
     * /

}
2. Modify the value of a private variable
/ **
 * Modify the value of private variables
 *
 * @param sender
 * /
-(IBAction) updatePrivateValue: (id) sender {
    Person * person = [[Person alloc] init];
    NSLog (@ "Data before modification:% @", [person description]);

    unsigned int count = 0; //
    Ivar * ivarList = class_copyIvarList ([Person class], & count);
    for (int i = 0; i <count; i ++) {
        Ivar var = ivarList [i];
        if (i == 0) // 1 means that the private variable age has just been printed on the second
        {
            object_setIvar (person, var, @ 28); // Change the value of private variable age to 28
        }

        if (i == 1) // private variable sex
        {
            object_setIvar (person, var, @ "女");
        }
    }

    NSLog (@ "Modified data ---:% @", [person description]);

    / ** The print result shows that the values of private variables age and sex have changed
     2016-06-02 19: 48: 32.218 RuntimeTestDemo [33349: 3554863] Data before modification: name: Zhang San-age: 18-sex: male-Hangzhou, Zhejiang Province
     2016-06-02 19: 48: 32.218 RuntimeTestDemo [33349: 3554863] Modified data ---: name: Zhang San-age: 450-sex: female-Hangzhou City, Zhejiang Province
     * /
}
3. Get all the methods of the class
/ **
         * Get all methods of the class (including private)
         *
         * @param sender sender
         * /
        -(IBAction) getAllMethod: (id) sender {
            unsigned int count = 0;
            Method * memberFuncs = class_copyMethodList ([Person class], & count); // Get all method names
            for (int i = 0; i <count; i ++) {
                SEL name = method_getName (memberFuncs [i]);
                const char * nameMethod = sel_getName (name); // Get the method name
                NSLog (@ "% s", nameMethod);
            }


            / ** Get all the methods of all .m files, including the get set method of attributes. Cxx_destruct system
             2016-06-02 19: 55: 26.411 RuntimeTestDemo [33544: 3558588] eat
             2016-06-02 19: 55: 26.412 RuntimeTestDemo [33544: 3558588] address
             2016-06-02 19: 55: 26.412 RuntimeTestDemo [33544: 3558588] .cxx_destruct
             2016-06-02 19: 55: 26.412 RuntimeTestDemo [33544: 3558588] description
             2016-06-02 19: 55: 26.412 RuntimeTestDemo [33544: 3558588] name
             2016-06-02 19: 55: 26.413 RuntimeTestDemo [33544: 3558588] setName:
             2016-06-02 19: 55: 26.413 RuntimeTestDemo [33544: 3558588] init
             2016-06-02 19: 55: 26.413 RuntimeTestDemo [33544: 3558588] setAddress:
             * /
        }
4. Dynamic addition method
/ **
 * Dynamic addition method
 *
 * @param sender sender
 * /
-(IBAction) addMethod: (id) sender {

// The meaning of class_addMethod function parameters:
// The first parameter Class cls, type
// The second parameter SEL name, the method being parsed
// The third parameter IMP imp, the specified implementation here means the specific implementation method myTestMethod
// The fourth parameter const char * types, the type of method (parameter of method) 0 means no parameter

// const char * cs = getprogname ();
    class_addMethod ([Person class], @selector (NewMethod: :), (IMP) myTestMethod, "[email protected]: [email protected]"); // A warning will be reported here and can be ignored
    // Call method [If using [per method] method! (No visible @interface error will be reported under ARC)]
    [person1 performSelector: @selector (NewMethod: :)];

}

// The specific implementation, that is, the method pointed to by IMP
int myTestMethod (id self, SEL _cmd, int var1, NSString * str)
{
    NSLog (@ "Already added method");
    return var1;
}
/ ** Printing result Print as follows
 2016-06-03 11: 00: 58.040 RuntimeTestDemo [34732: 3750980] method has been added
 * /

/ ** At this moment, print all methods of the acquisition class NewMethod :: This new method has been added
 2016-06-03 11: 00: 59.185 RuntimeTestDemo [34732: 3750980] NewMethod ::
 2016-06-03 11: 00: 59.185 RuntimeTestDemo [34732: 3750980] eat
 2016-06-03 11: 00: 59.185 RuntimeTestDemo [34732: 3750980] address
 2016-06-03 11: 00: 59.185 RuntimeTestDemo [34732: 3750980] .cxx_destruct
 2016-06-03 11: 00: 59.185 RuntimeTestDemo [34732: 3750980] description
 2016-06-03 11: 00: 59.185 RuntimeTestDemo [34732: 3750980] name
 2016-06-03 11: 00: 59.186 RuntimeTestDemo [34732: 3750980] setName:
 2016-06-03 11: 00: 59.186 RuntimeTestDemo [34732: 3750980] init
 2016-06-03 11: 00: 59.186 RuntimeTestDemo [34732: 3750980] setAddress:

 * /
5. Implementation of the exchange method
/ **
 * Method exchange
 *
 * @param sender sender
 * /
-(IBAction) methodExchange: (id) sender {

    [person1 test1]; // The output before the exchange

    Method method1 = class_getInstanceMethod ([person1 class], @selector (test1));
    Method method2 = class_getInstanceMethod ([person1 class], @selector (test2));

    // Method exchange
    method_exchangeImplementations (method1, method2);
    [person1 test1]; // output the result after exchange

    / ** Print the results of the test1 method after printing the results of test2
     2016-06-03 11: 27: 57.921 RuntimeTestDemo [35341: 3767704] I am the test1 method
     2016-06-03 11: 27: 57.922 RuntimeTestDemo [35341: 3767704] I am test2 method
     * /
}
6. Create a class dynamically
/ **
 * Dynamically add classes
 *
 * @param sender
 * /
-(IBAction) addClass: (id) sender {
    // Add a Student class
    Class classStudent = objc_allocateClassPair ([Person class], "Student", 0);

    // Add an NSStrig variable
    if (class_addIvar (classStudent, "schoolName", sizeof (NSString *), 0, "@")) {
        NSLog (@ "Add member variable schollName succeeded");
    }

    // Add methods for Student class
    if (class_addMethod (classStudent, @selector (printSchool), (IMP) printSchool, "[email protected]:")) {
        NSLog (@ "Add method printSchool succeeded");
    }

    // Register this class to the runtime system, you can use it
    objc_registerClassPair (classStudent); // returns void


    // Create class
    id student = [[classStudent alloc] init];

    NSString * schoolName = @ "Fujian Normal University";

    // Assign value to the variable just added
    [student setValue: schoolName forKey: @ "schoolName"];

    // Dynamic call
    [student performSelector: @selector (printSchool) withObject: nil];


    / ** print result
     2016-06-03 11: 49: 26.724 RuntimeTestDemo [35846: 3781380] The member variable schollName was added successfully
     2016-06-03 11: 49: 26.725 RuntimeTestDemo [35846: 3781380] The method printSchool was added successfully
     2016-06-03 11: 49: 26.725 RuntimeTestDemo [35846: 3781380] My school is Fujian Normal University
     * /
}

// The realization of the method
void printSchool (id self, SEL _cmd)
{
    NSLog (@ "My school is% @", [self valueForKey: @ "schoolName"]);
}
Six, Runtime experience

Runtime is very powerful. Here I am just a first-time experience. I still don't understand many things. I don't understand it. It is a preliminary understanding. It should be considered as a basic usage of runtime. To fully understand and fully apply it to actual projects, it still requires effort. It should be helpful for newcomers to understand, first of all know what the runtime is, the basic use of the runtime, and then dig slowly to gradually understand. I have uploaded the demo in the blog. You can download and run the log if you need it. If not enough, I hope to point out.

7. Demo address and reference blog, thanks

Demo address: http://download.csdn.net/detail/yj229201093/9540125 (2 points, more willful haha)
github address: https://github.com/yj229201093/RuntimeTestDemo
Thanks to the blogs of the two great gods for benefiting a lot.
Main reference link (Of course there are many good blogs on the Internet that have learned O (∩_∩) O haha ~)
1.http: //www.bkjia.com/IOSjc/1012702.html
2.http: //yulingtianxia.com/blog/2014/11/05/objective-c-runtime/
Basic use of Objective-C Runtime (first experience of iOS Runtime)

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.