iOS runtime practical application: member variables and properties

iOS runtime practical application: member variables and properties

[[164431]]

original

Preface

Before you begin, it is recommended to read the basic understanding of iOS runtime: iOS internal skills: runtime

During an interview, a guy encountered such a question: "Do you know the nature of member variables?" The guy was immediately confused. What is the nature of member variables? Member variables are member variables. They are just used in daily life. What is the deeper meaning? This article focuses on the definition and use of member variables and properties in runtime.

Noun Analysis

Member variables

1. Definition:

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

  1. typedef struct objc_ivar *Ivar;

2. Operation function:

  1. // Get all member variables  
  2. class_copyIvarList
  1. // Get the member variable name  
  2. ivar_getName
  1. // Get the member variable with the specified name  
  2. class_getInstanceVariable
  1. // Get member variable type code  
  2. ivar_getTypeEncoding
  1. // Set the value of an object member variable  
  2. object_setIvar
  1. // Get the value of an object member variable  
  2. object_getIvar

3. Use cases:

The Model header file is declared as follows:

  1. @interface Model : NSObject {
  2. NSString *_str1;
  3. }
  4. @property NSString * str2;
  5. @property (nonatomic, copy) NSDictionary * dict1;
  6. @end  

Get its member variables:

  1. unsigned int outCount = 0 ;
  2. Ivar * ivars = class_copyIvarList([Model class ], &outCount);
  3. for (unsigned int i = 0 ; i < outCount; i ++) {
  4. Ivar ivar = ivars[i];
  5. const   char * name = ivar_getName(ivar);
  6. const   char * type = ivar_getTypeEncoding(ivar);
  7. NSLog(@ "%s of type %s" , type, name);
  8. }
  9. free(ivars);

Print results:

  1. runtimeIvar[ 602 : 16885 ] _str1 of type @ "NSString"
  2. runtimeIvar[ 602 : 16885 ] _str2 of type @ "NSString"
  3. runtimeIvar[ 602 : 16885 ] _dict1 of type @ "NSDictionary"

property

1. Definition:

objc_property_t: The type of the declared property, a pointer to the objc_property structure

  1. typedef struct objc_property *objc_property_t;

2. Operation function:

  1. // Get all properties  
  2. class_copyPropertyList

Note: Using class_copyPropertyList will not get member variables without @property declaration

  1. // Get the attribute description string  
  2. property_getAttributes
  1. // Get the attribute name  
  2. property_getName
  1. // Get all attribute properties  
  2. property_copyAttributeList

illustrate:

The property_getAttributes function returns a list of objc_property_attribute_t structures. The objc_property_attribute_t structure contains name and value. The commonly used attributes are as follows:

  1. Property Type name value: T value: varies
  2. Encoding type name value: C (copy) & (strong) W (weak) empty (assign) etc. value: None
  3. Non/atomic name value: empty (atomic) N (Nonatomic) value: none
  4. Variable name name value: V value: changes

The description obtained using property_getAttributes is a general description of all the names and values ​​that property_copyAttributeList can obtain, such as T@"NSDictionary",C,N,V_dict1

3. Use cases:

  1. unsigned int outCount = 0 ;
  2. objc_property_t * properties = class_copyPropertyList([Model class ], &outCount);
  3. for (unsigned int i = 0 ; i < outCount; i ++) {
  4. objc_property_t property = properties[i];
  5. //Attribute name  
  6. const   char * name = property_getName(property);
  7. //Attribute description  
  8. const   char * propertyAttr = property_getAttributes(property);
  9. NSLog(@ "%s with property description %s" , propertyAttr, name);
  10.           
  11. //Attribute characteristics  
  12. unsigned int attrCount = 0 ;
  13. objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount);
  14. for (unsigned int j = 0 ; j < attrCount; j ++) {
  15. objc_property_attribute_t attr = attrs[j];
  16. const   char * name = attr.name;
  17. const   char * value = attr.value;
  18. NSLog(@ "Property description: %s Value: %s" , name, value);
  19. }
  20. free(attrs);
  21. NSLog(@ "\n" );
  22. }
  23. free(properties);

Print results:

  1. runtimeIvar[ 661 : 27041 ] str2 with property description T@ "NSString" ,&,V_str2
  2. runtimeIvar[ 661 : 27041 ] Property description: T Value: @ "NSString"  
  3. runtimeIvar[ 661 : 27041 ] Property Description: & Value:
  4. runtimeIvar[ 661 : 27041 ] Property Description: V Value: _str2
  5. runtimeIvar[ 661 : 27041 ]
  6. runtimeIvar[ 661 : 27041 ] dict1 with attribute description T@ "NSDictionary" ,C,N,V_dict1
  7. runtimeIvar[ 661 : 27041 ] Property Description: T Value: @ "NSDictionary"  
  8. runtimeIvar[ 661 : 27041 ] Property Description: C Value:
  9. runtimeIvar[ 661 : 27041 ] Property Description: N Value:
  10. runtimeIvar[ 661 : 27041 ] Property Description: V Value: _dict1
  11. runtimeIvar[ 661 : 27041 ]

Application Examples

1. Conversion from Json to Model

In development, I believe the most common thing is that interface data needs to be converted into Model (of course, if you take values ​​directly from Dict...), many developers also use well-known third-party libraries such as JsonModel, Mantle or MJExtension, etc. If you only use them without knowing why, it is really no different from "moving bricks". Next, we use runtime to parse json to assign values ​​to the Model.

Principle description: Use the function provided by runtime to traverse all attributes of the Model itself. If the attribute has a corresponding value in json, assign it.

Core method: Add method to NSObject category:

  1. - (instancetype)initWithDict:(NSDictionary *)dict {
  2.   
  3. if (self = [self init]) {
  4. //(1) Get the attributes of the class and the corresponding types of the attributes  
  5. NSMutableArray * keys = [NSMutableArray array];
  6. NSMutableArray * attributes = [NSMutableArray array];
  7. /*
  8. * example
  9. * name = value3 attribute = T@"NSString",C,N,V_value3
  10. * name = value4 attribute = T^i,N,V_value4
  11. */  
  12. unsigned int outCount;
  13. objc_property_t * properties = class_copyPropertyList([self class ], &outCount);
  14. for ( int i = 0 ; i < outCount; i ++) {
  15. objc_property_t property = properties[i];
  16. //Get the name of the property through the property_getName function  
  17. NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
  18. [keys addObject:propertyName];
  19. //The property name and @encode encoding can be obtained through the property_getAttributes function  
  20. NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
  21. [attributes addObject:propertyAttribute];
  22. }
  23. //Immediately release the memory pointed to by properties  
  24. free(properties);
  25.   
  26. //(2) Assign values ​​to attributes according to type  
  27. for (NSString * key in keys) {
  28. if ([dict valueForKey:key] == nil) continue ;
  29. [self setValue:[dict valueForKey:key] forKey:key];
  30. }
  31. }
  32. return self;
  33.   
  34. }

Readers can further think about:

  • How to identify and process the properties of basic data types

  • Handling of empty (nil, null) values

  • Processing of nested json (Dict or Array) in json

Try to solve the above problems, and you can also write your own full-featured Json to Model library.

2. Quick Archiving

Sometimes we need to archive some information, such as the user information class UserInfo, which will require overriding the initWithCoder and encodeWithCoder methods, and performing encode and decode operations on each attribute. Then the question is: when there are only a few attributes, it can be easily written, but what if there are dozens of attributes? Wouldn't it take forever to write? . . .

Principle description: Use the function provided by runtime to traverse all attributes of the Model itself, and encode and decode the attributes.

Core method: Override the method in the base class of Model:

  1. - (id)initWithCoder:(NSCoder *)aDecoder {
  2. if (self = [ super init]) {
  3. unsigned int outCount;
  4. Ivar * ivars = class_copyIvarList([self class ], &outCount);
  5. for ( int i = 0 ; i < outCount; i ++) {
  6. Ivar ivar = ivars[i];
  7. NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
  8. [self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
  9. }
  10. }
  11. return self;
  12. }
  13.   
  14. - ( void )encodeWithCoder:(NSCoder *)aCoder {
  15. unsigned int outCount;
  16. Ivar * ivars = class_copyIvarList([self class ], &outCount);
  17. for ( int i = 0 ; i < outCount; i ++) {
  18. Ivar ivar = ivars[i];
  19. NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
  20. [aCoder encodeObject:[self valueForKey:key] forKey:key];
  21. }
  22. }

3. Accessing private variables

We know that there are no real private variables and methods in OC. To make member variables private, they must be declared in the m file and not exposed to the outside world. If we know the name of the member variable, we can get the member variable through runtime and then get its value through getIvar.

method:

  1. Ivar ivar = class_getInstanceVariable([Model class ], "_str1" );
  2. NSString * str1 = object_getIvar(model, ivar);

Everyone is welcome to communicate and discuss.

<<:  Let's take a look at iOS local persistent storage (focusing on the SQLite database)

>>:  Comprehensive analysis of Activity startup mode

Recommend

Come and see! Today the moon is "blushing" and comes with a big Easter egg

Today, the most exciting astronomical phenomenon ...

Apple officially abandons iTunes! How to sync iPhone and iPad to Mac?

Recently, Apple officially released the new syste...

Fission Guide: What is traffic pool thinking?

The core idea of ​​" traffic pool thinking&q...

Product creation and verification operations for Douyin local life services

Douyin’s local life service makes targeted invita...

Neolithic "Meteor Hammer" Discovered!

Recently, Chen Zuhua, a citizen of Nanchang City,...

How to do information flow advertising? Highlight the key points

Information flow advertising, as a new breakthrou...

How to write heartfelt copy? 3 essential elements!

Copywriting is not a simple description of the pr...

How do animals become "love masters" every spring?

"Spring is here, everything is revived, and ...

iOS WeChat is updated again, and you can set video cover in Moments

[[417600]] Previously, iOS WeChat released the of...

Android mobile chip rankings released, Snapdragon 835 is not number one!

Smartphones have occupied most of people's li...

How to operate a qualified category?

Category operation is also called product operati...