Ivar: the instance variable type, which is a pointer to the objc_ivar structure

typedef struct objc_ivar *Ivar;
Copy the code

2. Operating functions:

// Get all member variables class_copyIvarListCopy the code
// Get the member variable name ivar_getNameCopy the code
// Get the member variable type encoding ivar_getTypeEncodingCopy the code
// Get the value of an object member variable object_getIvarCopy the code
// Set the value of an object member variable object_setIvarCopy the code

Example: The Model header file is declared as follows

  @interface Model : NSObject {
        NSString * _str1;
    }
    @property NSString * str2;
    @property (nonatomic, copy) NSDictionary * dict1;
    @end
Copy the code

Get its member variables:

unsigned int outCount = 0; Ivar * ivars = class_copyIvarList([Model class], &outCount); for (unsigned int i = 0; i < outCount; i ++) { Ivar ivar = ivars[i]; const char * name = ivar_getName(ivar); const char * type = ivar_getTypeEncoding(ivar); NSLog(@" %s of type %s ",type, name); } free(ivars);Copy the code

Print result:

RuntimeIvar [602:16885] _STR1 whose type is @"NSString" runtimeIvar[602:16885] _STR2 whose type is @"NSString" The type is @ "NSDictionary _dict1.Copy the code

Property 1. Definition: objc_property_t: The type of the declared property, which is a pointer to the objc_property structure

typedef struct objc_property *objc_property_t;
Copy the code

Note: Using class_copyPropertyList does not get member variables with no @property declaration

// Get property name property_getNameCopy the code
// Get Attributes Property Description String property_getAttributesCopy the code
// Get all properties property_copyAttributeListCopy the code

The property_getAttributes function returns a list of objc_property_attribute_t structures. The objc_property_attribute_t structure contains name and value.

Attribute Type Name Value: T value: changed Encoding type Name Value: C(copy) &(strong) W(weak) Empty (assign) Value: none Non-/ atomic Name value: empty (atomic) N(Nonatomic) value: None Variable Name Name Value: V value: changesCopy the code

The description obtained by using property_getAttributes is the overall description of all names and values that property_copyAttributeList can obtain, such as T@”NSDictionary”,C,N,V_dict1

3. Example:

unsigned int outCount = 0; objc_property_t * properties = class_copyPropertyList([Model class], &outCount); for (unsigned int i = 0; i < outCount; i ++) { objc_property_t property = properties[i]; // Const char * name = property_getName(property); Const char * propertyAttr = property_getAttributes(property); NSLog(@" %s of %s ", propertyAttr, name); Unsigned int attrCount = 0; objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount); for (unsigned int j = 0; j < attrCount; j ++) { objc_property_attribute_t attr = attrs[j]; const char * name = attr.name; const char * value = attr.value; NSLog(@" attribute description: %s value: %s", name, value); } free(attrs); NSLog(@"\n"); } free(properties);Copy the code

Print result:

RuntimeIvar [661:27041] attribute description T@"NSString",&,V_str2 str2 str2 attribute description: T value: @"NSString" runtimeIvar[661:27041] attribute description: & value: runtimeIvar[661:27041] attribute description: V value: _str2 runtimeIvar[661:27041] runtimeIvar[661:27041] Attribute description T@"NSDictionary",C,N,V_dict1 dict1 runtimeIvar[661:27041] Attribute description: T value: @"NSDictionary" runtimeIvar[661:27041] Attribute description: C value: runtimeIvar[661:27041] Attribute description: N value: RuntimeIvar [661:27041] Attribute Description: V value: _dict1 runtimeIvar[661:27041]Copy the code

The most common way to convert interface data to a Model is to convert it directly from Dict. Many developers also use well-known third party libraries such as JsonModel, Mantle, or MJExtension. If you only use JsonModel, Mantle, or MJExtension, it is no different to “move a brick”.

Principle description: Use the functions provided by Runtime to traverse all the attributes of Model. If the attributes have corresponding values in JSON, the values will be assigned. Core methods: Add methods to the class of NSObject:

- (instancetype)initWithDict:(NSDictionary *)dict {if (self = [self init]) {//(1) obtain class attributes and their corresponding type NSMutableArray * keys = [NSMutableArray array]; NSMutableArray * attributes = [NSMutableArray array]; /* * Example * name = value3 attribute = T@"NSString",C,N,V_value3 * name = value4 Attribute = T^ I,N,V_value4 */ unsigned int  outCount; objc_property_t * properties = class_copyPropertyList([self class], &outCount); for (int i = 0; i < outCount; i ++) { objc_property_t property = properties[i]; / / get the name of the property by property_getName function nsstrings * propertyName = [nsstrings stringWithCString: property_getName (property) encoding:NSUTF8StringEncoding]; [keys addObject:propertyName]; // The property_getAttributes function gets the name of the property and the @encode encoding NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding]; [attributes addObject:propertyAttribute]; } // Free the memory pointed to by properties immediately; For (NSString * key in keys) {if ([dict valueForKey:key] == nil) continue; // if ([dict valueForKey:key] == nil) continue; [self setValue:[dict valueForKey:key] forKey:key]; } } return self; }Copy the code

Sometimes we need to archive information, such as the user information class UserInfo, which requires overriding the initWithCoder and encodeWithCoder methods and encode and decode each attribute. So the question is: it’s easy to write when there are only a few attributes, but what if there are dozens? Shall it be written into eternity? .

Principle description: Use the functions provided by Runtime to traverse all attributes of Model, and encode and decode the attributes. Core methods: Override methods in Model base classes:

- (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { unsigned int outCount; Ivar * ivars = class_copyIvarList([self class], &outCount); for (int i = 0; i < outCount; i ++) { Ivar ivar = ivars[i]; NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)]; [self setValue:[aDecoder decodeObjectForKey:key] forKey:key]; } } return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { unsigned int outCount; Ivar * ivars = class_copyIvarList([self class], &outCount); for (int i = 0; i < outCount; i ++) { Ivar ivar = ivars[i]; NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)]; [aCoder encodeObject:[self valueForKey:key] forKey:key]; }}Copy the code

As we know, there is no real sense of private variables and methods in OC. To make member variables private, they should be declared in m files and not exposed to the public. If we know the name of the member variable, we can get the member variable from Runtime and get its value from getIvar. Methods:

Ivar ivar = class_getInstanceVariable([Model class], "_str1");
NSString * str1 = object_getIvar(model, ivar);
Copy the code

1. How to identify and process attributes of basic data types

NullSafe is a Category that, at runtime, sets the nasty null value to nil, which is safe and can send anything to a nil object without crashing. It’s a very easy category to use, you just add it to the project, you don’t have to do anything else, yeah, it’s that simple. For details, please go to Github. Github.com/nicklockwoo…

When a model value is a dictionary or collection Array, the internal elements need to be iterated and recursed until they are converted into valid JSON objects one by one.