An overview of the

I covered classes and objects in objective-C Runtime: Understanding Classes and objects in depth.

In this paper, focus on the details of the class implementation of the first content, mainly including the implementation of class member variables, attributes, methods and protocols and classification.

Before we get into member variables and attributes, we need to know a little bit about type encoding.

Type encoding

In Runtime, the compiler encodes the return value and argument type of each method as a string, which it associates with the method’s selector.

Because of the universality of the encoding scheme, the system provides the compiler instruction @encode to obtain the specific encoded string.

When given a type, @encode returns the string encoding for that type. These types can be primitive types such as ints and Pointers, or structures and classes.

In fact, any type that can be used as an argument to the sizeof() operation can perform the @encode() instruction.

All Type encodings in Objective-C are listed in the Type Encoding section of the Objective-C Runtime Programming Guide. It is important to note that many of these types are the same encoding types we use for archiving and distribution. But there are some that cannot be used while archiving, as follows:

Note: Objective-C is not supportedlong doubleType. @encode(long double) returns d, anddoubleIt's the same.Copy the code

For the type encoding of the array, the return string contains: the number of elements in the array and the type of the elements, as shown below:

int a[] = {1.2};
NSLog(@"type Coding = %s", @encode(typeof(a)));
Copy the code

The print result is as follows:

2018- 03- 28 22:46:28.253495+0800 RuntimeUsage[48760:1909814] type Coding = [2i]
Copy the code

For properties, there are also special Type encodings to indicate that the Property is read-only, copy, retain, and so on, as described in the Property Type String.

Member variables and attributes

There are three aspects to note in this section on member variables and properties: Ivar, objC_property_t basic data structures, and Associated Objects. Among them, related content about the associated object has been elaborated in the previous article.

### Basic data structure

Data structures for member variables (Ivar)

Struct objc_ivar (Objc/ Runtime.h, Objc/runtime.h, Objc/runtime.h, Objc/runtime.h, Objc/runtime.h, Objc/runtime.h, Objc/runtime.h, Objc/runtime.h

typedef struct objc_ivar *Ivar;
Copy the code

Struct objc_ivar data structure as follows:

struct objc_ivar {
    char *ivar_name OBJC2_UNAVAILABLE; // The variable name.
    char *ivar_type OBJC2_UNAVAILABLE; // Variable type.
    int ivar_offset OBJC2_UNAVAILABLE; // Base address offset, used when addressing member variables.
#ifdef __LP64__
    int space OBJC2_UNAVAILABLE;
#endif
} 
Copy the code

Property data structure

The property data structure is as follows:

typedef struct objc_property *objc_property_t;
Copy the code

The data structure of attributes is as follows:

typedef struct {
    const char * _Nonnull name;           /**< The name of the attribute */
    const char * _Nonnull value;          /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
Copy the code

Relationships between member variables and attributes

  • In essence, an attribute must correspond to a member variable, but an attribute is not just a member variable. It also encapsulates the member variable according to the definition of its corresponding property: providing Getter/Setter methods, memory management policies, thread safety mechanisms, and so on.

Operation methods of member variables and attributes

Member variables

The related functions of member variables are as follows:

// Get the member variable name
const char * ivar_getName ( Ivar v );
// Get the member variable type encoding
const char * ivar_getTypeEncoding ( Ivar v );
// Get the offset of the member variable
ptrdiff_t ivar_getOffset ( Ivar v );
Copy the code
  • ivar_getOffsetFunctions, for typesidOr an instance variable of another object typeobject_getIvarandobject_setIvarTo access member variables directly without using offsets.
associations

The associated object functions are as follows:

// Set the associated object
void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy );
// Get the associated object
id objc_getAssociatedObject ( id object, const void *key );
// Remove the associated object
void objc_removeAssociatedObjects ( id object );
Copy the code
attribute

Attribute related functions are as follows:

// Get the attribute name
const char * property_getName ( objc_property_t property );
// Gets the attribute description string
const char * property_getAttributes ( objc_property_t property );
// Gets the property specified in the property
char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );
// Get the property list for the property
objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );
Copy the code
  • property_copyAttributeValueFunction, which returnschar *Need to be called after usefree()Release.
  • property_copyAttributeListFunction that needs to be called after the return value is usedfree()Release.

Sample code for runtime manipulation of member variables and properties

NSString * runtimePropertyGetterIMP(id self, SEL _cmd){
    Ivar ivar = class_getInstanceVariable([self class], "_runtimeProperty");
    
    return object_getIvar(self, ivar);
}

void runtimePropertySetterIMP(id self, SEL _cmd, NSString *value){
    Ivar ivar = class_getInstanceVariable([self class], "_runtimeProperty");
    NSString *aValue = (NSString *)object_getIvar(self, ivar);
    if (![aValue isEqualToString:value]) {
        object_setIvar(self, ivar, value);
    }
}

- (void)verifyPropertyAndIvar{
    
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
    
    //1, Add property and getter/setter method
    Class cls = objc_allocateClassPair([Animal class], "Panda".0);
    
    //add instance variable
    BOOL isSuccess = class_addIvar(cls, "_runtimeProperty".sizeof(cls), log2(sizeof(cls)), @encode(NSString));
    NSLog(@"% @", isSuccess ? @"Success" : @"Failure");/ / print success
    
    //add attributes
    objc_property_attribute_t type = {"T"."@\"NSString\""};
    objc_property_attribute_t ownership = {"C".""};//C = Copy
    objc_property_attribute_t isAutomic = {"N".""};// N = nonatomic
    objc_property_attribute_t backingVar = {"V"."_runtimeProperty"};
    objc_property_attribute_t attrubutes[] = {type, ownership, isAutomic, backingVar};
    class_addProperty(cls, "runtimeProperty", attrubutes, 4);
    class_addMethod(cls, @selector(runtimeProperty), (IMP)runtimePropertyGetterIMP, "@ @.");
    class_addMethod(cls, @selector(setRuntimeProperty), (IMP)runtimePropertySetterIMP, "V@:");
    
    objc_registerClassPair(cls);
    
    //2, print all properties
    unsigned int count = 0;
    objc_property_t *properties = class_copyPropertyList(cls, &count);
    for (int32_t i = 0; i < count; i ++) {
        objc_property_t property = properties[I];
        NSLog(@"%s, %s\n", property_getName(property), property_getAttributes(property));
        //print: _runtimeProperty, T@"NSString",C,N,V_runtimeProperty
    }
    free(properties);
    
    //3, print all Ivar
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList(cls, &outCount);
    for (int32_t i = 0; i < outCount; i ++) {
        Ivar ivar = ivars[I];
        NSLog(@"%s, %s\n", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
        //print:_runtimeProperty, {NSString=#}
       
    }
    free(ivars);
    
    / / 4, the use of the property
    id panda = [[cls alloc] init];
    [panda performSelector:@selector(setRuntimeProperty) withObject:@"set-property"];
    NSString *propertyValue = [panda performSelector:@selector(runtimeProperty)];
    NSLog(@"return value = %@", propertyValue);
    //print: return value = set-property
    
    / / 5 and destory
    panda = nil;
    objc_disposeClassPair(cls);
    
    
#pragma clang diagnostic pop
    
}
Copy the code

The above code prints information:

Successful runtimeProperty, T @"NSString",C,N,V_runtimeProperty
_runtimeProperty, {NSString=#}
return value = set-property
Copy the code
  • In the code above, we created it dynamically at run timeAnimalA subclass ofPanda;
  • Then add Ivar to it dynamically:_runtimePropertyCorresponding Property:runtimePropertyAnd the correspondingGetter/SetterMethods:runtimeProperty``setRuntimeProperty;
  • Then we traversed and printedPandaIvar list and Property list;
  • And then createPandaAn instance ofpanda, and uses Property;
  • We ended up destroying itpandaPanda.

Here are a few things to note:

  • We can’t useclass_addIvar()Function to add to an existing class IvarAnd,class_addIvar()Only in theobjc_allocateClassPair()objc_registerClassPair()Call between;
  • For details about the types of characters used to add attributes, see Property Type String.
  • By adding an attribute and its corresponding member variable, we can still pass[obj valueForKey:@"propertyName"];Get the property value.

summary

This article mainly explains the use of member variables and attributes, especially the use of associated objects. Hopefully, after reading this article, you will have a deeper understanding of member variables and attributes.

reference

  • Objective-C Runtime Programming Guide

Scan the following QR code, welcome to follow my personal wechat official account: Ape Perspective dynamics (ID:iOSDevSkills), you can leave a message on wechat official account, more exciting technical articles, looking forward to your participation! Discuss and grow together! Attack the lion!