OBJECTIVE-C Runtime Two: member variables and properties

Source: Internet
Author: User

In the previous article, we introduced the class-and object-related content in runtime, and from this chapter we will discuss the content of class implementation details, including the implementation of member variables, properties, methods, protocols, and classifications in the class.

The main content of this chapter will be gathered at runtime to handle member variables and attributes. Before discussing this, let's start with an important concept: type coding.

Type encoding (Type Encoding)

As a complement to runtime, the compiler encodes the return value and parameter type of each method as a string and associates it with the selector of the method. This coding scheme is also very useful in other situations, so we can use the @encode compiler directive to get it. When given a type, @encode returns the string encoding of this type. These types can be basic types such as int, pointers, or structs, classes, and so on. In fact, any type that can be used as the sizeof () action parameter can be applied to @encode ().

All of the 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 as the encoding types we use for archiving and distribution. However, some cannot be used when archiving.

Note: Objective-c does not support long double types. A @encode (long double) returns D, the same as double.

The type encoding of an array is in square brackets, which contains the number of array elements and the element type. As in the following example:

float a[] = {1.0, 2.0, 3.0};NSLog(@"array encoding type: %s", @encode(typeof(a)));

The output is:

2014-10-28 11:44:54.731 RuntimeTest[942:50791] array encoding type: [3f]

Other types can refer to type Encoding, which is not in detail here.

In addition, there are encoding types, @encode although they are not returned directly, they can be used as type qualifiers for the methods declared in the protocol. You can refer to type Encoding.

For attributes, there are also special type encodings to indicate that the property is read-only, copied, retain, and so on, and the details can be referenced by the property type String.

member variables, properties

There are not many related data structures for member variables and attributes in runtime, only three, and they are simple. There is, however, a very practical and often overlooked feature, the association object, which we will discuss in detail in this section.

Base data Type Ivar

Ivar is the type that represents the instance variable, which is actually a pointer to the Objc_ivar struct, which is defined as follows:

typedef struct objc_ivar *Ivar;struct objc_ivar {    char *ivar_name                 OBJC2_UNAVAILABLE;  // 变量名    char *ivar_type                 OBJC2_UNAVAILABLE;  // 变量类型    int ivar_offset                 OBJC2_UNAVAILABLE;  // 基地址偏移字节#ifdef __LP64__    int space                       
objc_property_t

Objc_property_t is the type of the property that represents the Objective-c declaration, which is actually a pointer to the Objc_property struct, which is defined as follows:

typedef struct objc_property *objc_property_t;
objc_property_attribute_t

objc_property_attribute_t defines the attribute of a property (attribute), which is a struct, defined as follows:

typedef struct {    const char *name;           // 特性名    const char *value;          // 特性值} objc_property_attribute_t;
Associative objects (associated object)

Association objects are a very useful feature in runtime, but they can be easily overlooked.

An association object is similar to a member variable, but is added at run time. We usually place the member variable (Ivar) in the header file of the class declaration, or behind the @implementation of the class implementation. However, there is a disadvantage that we cannot add member variables to the classification. If we try to add a new member variable to the category, the compiler will make an error.

We may want to solve this problem by using (or even abusing) global variables. But these are not Ivar, because they are not connected to a separate instance. Therefore, this method is seldom used.

Objective-c for this issue, a solution is provided: the association objects (associated object).

We can think of an associative object as a Objective-c object (such as a dictionary) that is connected to an instance of a class by a given key. However, because the C interface is used, key is a void pointer (const void *). We also need to specify a memory management policy to tell the runtime how to manage the memory of this object. This memory-managed policy can be specified by the following values:

OBJC_ASSOCIATION_ASSIGNOBJC_ASSOCIATION_RETAIN_NONATOMICOBJC_ASSOCIATION_COPY_NONATOMICOBJC_ASSOCIATION_RETAINOBJC_ASSOCIATION_COPY

When the host object is disposed, the associated object is processed according to the specified memory management policy. If the specified policy is assign, the associated object is not freed when the host is disposed, and if retain or copy is specified, the associated object is freed when the host is disposed. We can even choose whether it is automatic retain/copy. This is useful when we need to process multithreaded code that accesses the associated object in multiple threads.

What we need to do to connect an object to other objects is the following two lines of code:

static char myKey;objc_setAssociatedObject(self, &myKey, anObject, OBJC_ASSOCIATION_RETAIN);

In this case, the self object acquires a new associated object AnObject, and the memory management policy is automatically retain the associated object, and when the self object is disposed, the associated object is automatically released. Also, if we use the same key to associate another object, the previously associated object is automatically freed, in which case the previous associated object is properly disposed of, and the new object uses its memory.

id anObject = objc_getAssociatedObject(self, &myKey);

We can use the Objc_removeassociatedobjects function to remove an associated object, or use the Objc_setassociatedobject function to set the associated object specified by key to nil.

Let's use the example below to illustrate how the associated object is used.

Suppose we want to dynamically connect a tap gesture operation to any UIView, and specify the actual action after the click as needed. At this point we can associate a gesture object with the action's block object into our UIView object. The task is divided into two parts. First, if necessary, we will create a gesture recognition object and make it and block as the associated object. As shown in the following code:

- (void)setTapActionWithBlock:(void (^)(void))block{    UITapGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerTapGestureKey);    if (!gesture)    {        gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForTapGesture:)];        [self addGestureRecognizer:gesture];        objc_setAssociatedObject(self, &kDTActionHandlerTapGestureKey, gesture, OBJC_ASSOCIATION_RETAIN);    }    objc_setAssociatedObject(self, &kDTActionHandlerTapBlockKey, block, OBJC_ASSOCIATION_COPY);}

This code detects the associated object for gesture recognition. If not, the association relationship is created and established. At the same time, the incoming block object is connected to the specified key. Note The associated memory management policy for the Block object.

Gesture recognition objects require a target and action, so next we define the processing method:

- (void)__handleActionForTapGesture:(UITapGestureRecognizer *)gesture{    if (gesture.state == UIGestureRecognizerStateRecognized)    {        void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerTapBlockKey);        if (action)        {            action();        }    }}

We need to detect the state of the gesture recognition object, because we only need to perform the action when the click Gesture is recognized.

As we can see from the above example, the association object is not complicated to use. It allows us to dynamically enhance the existing functionality of the class. We can use this feature flexibly in the actual coding.

Member variables, action method member variables for properties

The member variable operation contains the following functions:

// 获取成员变量名const char * ivar_getName ( Ivar v );// 获取成员变量类型编码const char * ivar_getTypeEncoding ( Ivar v );// 获取成员变量的偏移量ptrdiff_t ivar_getOffset ( Ivar v );

The Ivar_getoffset function, for instance variables of type IDs or other object types, can call Object_getivar and Object_setivar to directly access member variables without using offsets.

Associating objects

The associated object operation functions include the following:

// 设置关联对象void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy );// 获取关联对象id objc_getAssociatedObject ( id object, const void *key );// 移除关联对象void objc_removeAssociatedObjects ( id object );

The associated objects and related instances have been discussed earlier and are not repeated here.

Property

Property manipulation related functions include the following:

// 获取属性名const char * property_getName ( objc_property_t property );// 获取属性特性描述字符串const char * property_getAttributes ( objc_property_t property );// 获取属性中指定的特性char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );// 获取属性的特性列表objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );

The Property_copyattributevalue function returns a char * that needs to be freed after it is exhausted. Property_copyattributelist function, the return value needs to call free () after it is exhausted.

Instance

Assuming such a scenario, we get the same dictionary data from the server's two different interfaces, but the two interfaces are written by two people, and the same information is represented using different fields. When we receive the data, we can save the data in the same object. The object class is defined as follows:

@interface MyObject: NSObject@property (nonatomic, copy) NSString    *   name;                  @property (nonatomic, copy) NSString    *   status;                 @end

The dictionary data returned by interface A and B is as follows:

@{@"name1": "张三", @"status1": @"start"}@{@"name2": "张三", @"status2": @"end"}

The usual method is to write two methods to do the conversion, but if you have the flexibility to use runtime, you can only implement a conversion method, for this, we need to define a mapping dictionary (global variable)

static NSMutableDictionary *map = nil;@implementation MyObject+ (void)load{    map = [NSMutableDictionary dictionary];    map[@"name1"]                = @"name";    map[@"status1"]              = @"status";    map[@"name2"]                = @"name";    map[@"status2"]              = @"status";}@end

The above code maps the different fields in the two dictionaries to the same attributes in the MyObject, so that the conversion method can be handled as follows:

- (void)setDataWithDic:(NSDictionary *)dic{    [dic enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {        NSString *propertyKey = [self propertyForKey:key];        if (propertyKey)        {            objc_property_t property = class_getProperty([self class], [propertyKey UTF8String]);            // TODO: 针对特殊数据类型做处理            NSString *attributeString = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];            ...            [self setValue:obj forKey:propertyKey];        }    }];}

Of course, the premise that a property can be handled in this way is that it supports KVC.

Summary

In this chapter we discuss the content related to member variables and attributes in runtime. Member variables and attributes are the data base of the class, and the use of related operations in runtime makes it more flexible to handle the work related to class data.

Note: If there is a mistake, please correct me, welcome to add QQ Friends: 1318202110 (South peak son)

http://southpeak.github.io/blog/2014/10/30/objective-c-runtime-yun-xing-shi-zhi-er-:cheng-yuan-bian-liang-yu-shu-xing/

OBJECTIVE-C Runtime Two: member variables and properties

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.