Detailed use of Runtime in IOS, and use of runtimeios

Source: Internet
Author: User

Detailed use of Runtime in IOS, and use of runtimeios

Because I used to write things in unknown notes, and I have never seen any of my articles, I will start to use the blog community to communicate with you today. Well, there are not so many nonsense. Next I will introduce runtime to you.

  

### 1. Introduction to runtime
* RunTime is short for running. OC is the 'runtime Mechanism ', that is, some mechanisms during the runtime, the most important of which is the message mechanism.
* For C language, 'function calls determine which function to call during compilation '.
* For OC functions, they belong to the 'dynamic call process' and cannot decide which function to call during compilation, the corresponding function can be called only when the function is running.
* Facts:
* In the compilation phase, OC can 'call any function'. Even if this function is not implemented, no error will be reported if it has been declared.
* During the compilation phase, an error is reported when the C language calls 'unimplemented functions.

### 2. Functions of runtime

#### 1. Send a message
* The essence of a method call is to let an object send messages.
* Objc_msgSend: only objects can send messages. Therefore, it starts with objc.
* Before using the 'message' mechanism, you must import # import <objc/message. h>
* Simple message mechanism

'''
// Create a person object
Person * p = [[Person alloc] init];

// Call the object Method
[P eat];

// Essence: Let the object send messages
Objc_msgSend (p, @ selector (eat ));

// Call methods:
// The first method is called by class name.
[Person eat];
// The second method is called through a class object.
[[Person class] eat];

// Call the class method with the class name. The underlying layer will automatically convert the class name into a class object call
// Essence: Let the Class Object send messages
Objc_msgSend ([Person class], @ selector (eat ));

'''
* Message mechanism principle: Implement object ing table searching based on method ID SEL
*! [](Snip20151013_4.png)

#### 2. Exchange Methods
* Development and Use Cases: The method functions provided by the system are insufficient. Some functions are extended for the methods provided by the system and the original functions are maintained.
* Method 1: Inherit the system class and override the method.
* Method 2: Use runtime and exchange method.


'''
@ Implementation ViewController


-(Void) viewDidLoad {
[Super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Requirement: Provides the imageNamed method with the function to determine whether the image is loaded successfully each time.
// Step 1: first create a classification and define a method that can load images and print images + (instancetype) imageWithName :( NSString *) name;
// Step 2: You can call imageWithName by exchanging the imageNamed and imageWithName implementations, and indirectly call the imageWithName implementations.
UIImage * image = [UIImage imageNamed: @ "123"];

}

@ End


@ Implementation UIImage (Image)
// Called when category is loaded into memory
+ (Void) load
{
// Exchange method

// Obtain the imageWithName method address
Method imageWithName = class_getClassMethod (self, @ selector (imageWithName :));

// Obtain the imageWithName method address
Method imageName = class_getClassMethod (self, @ selector (imageNamed :));

// Exchange method address, which is equivalent to the exchange Implementation Method
Method_exchangeImplementations (imageWithName, imageName );


}

// The system method imageNamed cannot be rewritten in the category, because the system function will be overwritten, and super cannot be called in the category.

// The image can be loaded and printed
+ (Instancetype) imageWithName :( NSString *) name
{

// ImageWithName is called here, which is equivalent to imageName
UIImage * image = [self imageWithName: name];

If (image = nil ){
NSLog (@ "loading empty images ");
}

Return image;
}


@ End
'''

* Switching principle:
* Before exchange:
! [](Snip20151013_2.png)


* After exchange:
! [](Snip20151013_3.png)


#### 3. Dynamic Addition Method
* Development Application Scenario: if there are many class methods, loading classes to the memory is also resource-consuming. You need to generate a ing table for each method. You can use dynamic ing for a class, add a solution.
* Classic interview questions: Do you have used javasmselector? In fact, I mainly want to ask if you have dynamically added methods.
* Easy to use

'''
@ Implementation ViewController

-(Void) viewDidLoad {
[Super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

Person * p = [[Person alloc] init];

// The default person, which does not implement the eat method, can be called by the performSelector, but an error is reported.
// No error will be reported when you add a method dynamically.
[P performSelector: @ selector (eat)];

}


@ End


@ Implementation Person
// Void (*)()
// The default method has two implicit parameters,
Void eat (id self, SEL sel)
{
NSLog (@ "% @", self, NSStringFromSelector (sel ));
}

// When an object calls an unimplemented method, it calls this method for processing and transmits the corresponding list of methods.
// It can be used to determine whether the unimplemented method is the one we want to dynamically add.
+ (BOOL) resolveInstanceMethod :( SEL) sel
{

If (sel = @ selector (eat )){
// Add the eat method dynamically

// The first parameter: the class to which the method is added
// The second parameter is the method number for adding a method.
// Third parameter: function implementation of the add method (function address)
// The fourth parameter: function type (Return Value + parameter type) v: void @: Object-> self: Indicates SEL-> _ cmd
Class_addMethod (self, @ selector (eat), eat, "v @:");

}

Return [super resolveInstanceMethod: sel];
}
@ End

'''


#### 4. Add attributes to a category
* Principle: declare attributes for a class. In essence, adding associations to this class does not directly add the memory space of this value to the class storage space.

'''

@ Implementation ViewController

-(Void) viewDidLoad {
[Super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

// Dynamically Add the attribute name to the system NSObject class

NSObject * objc = [[NSObject alloc] init];
Objc. name = @ "Tom ";
NSLog (@ "% @", objc. name );

}


@ End


// Define the associated key
Static const char * key = "name ";

@ Implementation NSObject (Property)

-(NSString *) name
{
// Obtain the associated value based on the associated key.
Return objc_getAssociatedObject (self, key );
}

-(Void) setName :( NSString *) name
{
// The first parameter: Specifies the object to be associated.
// The second parameter: the associated key. It is obtained through this key.
// The third parameter: the associated value
// Fourth parameter: associated policy
Objc_setAssociatedObject (self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC );
}

@ End


'''


#### 5. dictionary-to-Model
* Design model: the first step of dictionary-to-model conversion
* Model attributes, usually one-to-one correspondence with the keys in the dictionary
* Q: Is it slow to generate model attributes one by one?
* Requirement: whether or not the corresponding attribute can be automatically generated based on a dictionary.
* Solution: provides a category to generate corresponding attribute strings Based on the dictionary.

'''
@ Implementation NSObject (Log)


// Automatically print the property string
+ (Void) resolveDict :( NSDictionary *) dict {

// Concatenate the property string code
NSMutableString * strM = [NSMutableString string];

// 1. traverse the dictionary, retrieve all keys in the dictionary, and generate the corresponding attribute code
[Dict enumerateKeysAndObjectsUsingBlock: ^ (id _ Nonnull key, id _ Nonnull obj, BOOL * _ Nonnull stop ){

// The type is frequently changed and extracted
NSString * type;

If ([obj isKindOfClass: NSClassFromString (@ "_ NSCFString")]) {
Type = @ "NSString ";
} Else if ([obj isKindOfClass: NSClassFromString (@ "_ NSCFArray")]) {
Type = @ "NSArray ";
} Else if ([obj isKindOfClass: NSClassFromString (@ "_ NSCFNumber")]) {
Type = @ "int ";
} Else if ([obj isKindOfClass: NSClassFromString (@ "_ NSCFDictionary")]) {
Type = @ "NSDictionary ";
}


// Attribute string
NSString * str;
If ([type containsString: @ "NS"]) {
Str = [NSString stringWithFormat: @ "@ property (nonatomic, strong) % @ * % @;", type, key];
} Else {
Str = [NSString stringWithFormat: @ "@ property (nonatomic, assign) %;", type, key];
}

// Each time an attribute string is generated, a new line is automatically wrapped.
[StrM appendFormat: @ "\ n % @ \ n", str];

}];

// Print the concatenated string.
NSLog (@ "% @", strM );

}


@ End

'''

* Dictionary-to-model Conversion Method 1: KVC

'''
@ Implementation Status


+ (Instancetype) statusWithDict :( NSDictionary *) dict
{
Status * status = [[self alloc] init];

[Status setValuesForKeysWithDictionary: dict];

Return status;

}

@ End

'''


* Disadvantages of KVC dictionary-to-model conversion: it must be ensured that the attributes in the model correspond to the keys in the dictionary one by one.
* If they are inconsistent, '[<Status 0x7fa74b545d60> setValue: forUndefinedKey:]' will be called.
The error 'key' cannot be found.
* Analysis: If the attributes in the model do not match the dictionary key one by one, the system will call 'setvalue: forUndefinedKey: 'to report an error.
* Solution: override 'setvalue: forUndefinedKey: 'of the object and overwrite the system method,
You can continue to use KVC to convert the dictionary into a model.

'''
-(Void) setValue :( id) value forUndefinedKey :( NSString *) key
{

}

'''

* Dictionary-to-model Conversion Method 2: Runtime
* Idea: Use runtime to traverse all the attributes in the model, search for the key in the dictionary based on the attribute name of the model, obtain the corresponding value, and assign values to the attributes of the model.
* Step: Provide an NSObject category for conversion from dictionary to model. All models can be converted through this classification later.

'''

@ Implementation ViewController

-(Void) viewDidLoad {
[Super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

// Parse the Plist File
NSString * filePath = [[NSBundle mainBundle] pathForResource: @ "status. plist" ofType: nil];

NSDictionary * statusDict = [NSDictionary dictionaryWithContentsOfFile: filePath];

// Obtain the dictionary Array
NSArray * dictArr = statusDict [@ "statuses"];

// Automatically generate the Model Property string
// [NSObject resolveDict: dictArr [0] [@ "user"];


_ Statuses = [NSMutableArray array];

// Traverse the dictionary Array
For (NSDictionary * dict in dictArr ){

Status * status = [Status modelWithDict: dict];

[_ Statuses addObject: status];

}

// Test Data
NSLog (@ "% @", _ statuses, [_ statuses [0] user]);


}

@ End

@ Implementation NSObject (Model)

+ (Instancetype) modelWithDict :( NSDictionary *) dict
{
// Train of thought: traverse all attributes in the model-use Runtime

// 0. Create the corresponding object
Id objc = [[self alloc] init];

// 1. assign values to the member attributes of an object using runtime

// Class_copyIvarList: obtains all member attributes in the class.
// Ivar: Meaning of member attributes
// The first parameter indicates which class the member attribute is obtained.
// The second parameter indicates the number of member attributes of the class. If an Int variable address is input, the variable is automatically assigned a value.
// Return value Ivar *: indicates an ivar array. All member attributes are placed in an array and can be obtained from all returned arrays.
/* Similar to the following method

Ivar ivar;
Ivar ivar1;
Ivar ivar2;
// Define an ivar array
Ivar a [] = {ivar, ivar1, ivar2 };

// Use an Ivar * pointer to point to the first element of the array
Ivar * ivarList =;

// Access the first element of the Array Based on the pointer
IvarList [0];

*/
Unsigned int count;

// Obtain all member attributes in the class
Ivar * ivarList = class_copyIvarList (self, & count );

For (int I = 0; I <count; I ++ ){
// Retrieves the corresponding member attributes from the Array Based on the badge
Ivar ivar = ivarList [I];

// Obtain the member attribute name
NSString * name = [NSString stringwithuf8string: ivar_getName (ivar)];

// Process the member property name-> key in the dictionary
// Start from the first badge
NSString * key = [name substringFromIndex: 1];

// Find the corresponding value in the dictionary based on the member attribute name
Id value = dict [key];

// Second-level conversion: if there are still dictionaries in the dictionary, you also need to convert the corresponding dictionary into a model.
// Determine whether the value is a dictionary.
If ([value isKindOfClass: [NSDictionary class]) {
// Dictionary-to-Model
// Obtain the model Class Object and call modelWithDict
// The Class Name of the model is known, which is the type of the member attribute.

// Obtain the member attribute type
NSString * type = [NSString stringwithuf8string: ivar_getTypeEncoding (ivar)];
// The generated @ "@ \" User \ "" type-"@" User "in the OC string \"-> ", \ is the meaning of escape, no characters
// Crop a string
Nsange range = [type rangeOfString: @ "\" "];

Type = [type substringFromIndex: range. location + range. length];

Range = [type rangeOfString: @ "\" "];

// Specifies the badge to which the image is cropped, excluding the current badge.
Type = [type substringToIndex: range. location];


// Generate Class Object Based on the string class name
Class modelClass = NSClassFromString (type );

If (modelClass) {// a corresponding model needs to be transferred

// Convert dictionary to Model
Value = [modelClass modelWithDict: value];
}


}

// Three-level conversion: NSArray is also a dictionary that converts the dictionary in the array into a model.
// Determine whether the value is an array.
If ([value isKindOfClass: [NSArray class]) {
// Determine whether the corresponding class implements the dictionary array to model array Protocol
If ([self respondsToSelector: @ selector (arrayContainModelClass)]) {

// Convert to the id type to call methods of any object
Id idSelf = self;

// Obtain the dictionary model in the array
NSString * type = [idSelf arrayContainModelClass] [key];

// Generate the Model
Class classModel = NSClassFromString (type );
NSMutableArray * arrM = [NSMutableArray array];
// Traverse the dictionary array to generate the model Array
For (NSDictionary * dict in value ){
// Dictionary-to-Model
Id model = [classModel modelWithDict: dict];
[ArrM addObject: model];
}

// Assign a model array to value
Value = arrM;

}
}


If (value) {// if there is a value, you need to assign a value to the model attribute.
// Assign values to attributes in the model using KVC
[Objc setValue: value forKey: key];
}

}

Return objc;
}

@ End


'''

 

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.