OBJECTIVE-C Runtime Two: member variables and properties

Source: Internet
Author: User
Tags list of attributes
The main content of this chapter will be gathered in the handling of member variables and attributes in Runtime. Before discussing, let's introduce an important concept: type encoding.

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

In the Type Encoding section of the Objective-C Runtime Programming Guide, all type encodings in Objective-C are listed. Note that many of these types are the same as the encoding types we use for archiving and distribution. But some cannot be used during archiving.

Note: Objective-C does not support long double types. @encode (long double) returns d, which is the same as double.

The type code of an array is in square brackets; it contains the number of array elements and the element type. For example:

float a [] = {1.0, 2.0, 3.0};
1
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]
For other types, please refer to Type Encoding.

In addition, there are some encoding types, although @encode will not return them directly, but they can be used as the type qualifier of the method declared in the protocol. You can refer to Type Encoding.

For properties, there will be some special type codes to indicate that the property is read-only, copy, retain, etc. For details, please refer to Property Type String.

Member variables, attributes
There are not many related data structures about member variables and attributes in Runtime, there are only three, and they are all very simple. But there is another very useful but often overlooked feature, that is, associated objects, 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 structure, which is defined as follows:

typedef struct objc_ivar * Ivar;

struct objc_ivar {

    char * ivar_name OBJC2_UNAVAILABLE; // variable name

    char * ivar_type OBJC2_UNAVAILABLE; // variable type

    int ivar_offset OBJC2_UNAVAILABLE; // base address offset byte

#ifdef __LP64__

    int space OBJC2_UNAVAILABLE;

#endif

}
objc_property_t
objc_property_t is the type representing the properties declared by Objective-C. It is actually a pointer to the objc_property structure, which is defined as follows:

typedef struct objc_property * objc_property_t;
objc_property_attribute_t
objc_property_attribute_t defines the attributes of an attribute. It is a structure and is defined as follows:

typedef struct {

    const char * name; // feature name

    const char * value; // characteristic value

} objc_property_attribute_t;
Associated Object
Associated objects are a very useful feature in Runtime, but may be easily overlooked.

Associated objects are similar to member variables, but they are added at runtime. We usually put member variables (Ivar) in the header file of the class declaration, or behind @implementation of the class implementation. But there is a disadvantage, we cannot add member variables to the classification. If we try to add new member variables to the classification, the compiler will report an error.

We may hope 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 rarely used.

Objective-C provides a solution to this problem: the Associated Object.

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

OBJC_ASSOCIATION_ASSIGN

OBJC_ASSOCIATION_RETAIN_NONATOMIC

OBJC_ASSOCIATION_COPY_NONATOMIC

OBJC_ASSOCIATION_RETAIN

OBJC_ASSOCIATION_COPY
When the host object is released, the associated object is processed according to the specified memory management strategy. If the specified strategy is assign, the associated object will not be released when the host is released; and if retain or copy is specified, the associated object will be released when the host is released. We can even choose whether to retain / copy automatically. This is useful when we need to handle multithreaded code that accesses associated objects in multiple threads.

All we need to do to connect one object to another is the following two lines of code:

static char myKey;

objc_setAssociatedObject (self, & myKey, anObject, OBJC_ASSOCIATION_RETAIN);
In this case, the self object will acquire a new associated object anObject, and the memory management strategy is to automatically retain the associated object. When the self object is released, the associated object will be automatically released. In addition, if we use the same key to associate another object, the previously associated object will be automatically released. In this case, the previous associated object will be properly disposed of, and the new object will use 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 an example to demonstrate the use of associated objects.

Suppose we want to dynamically connect a Tap gesture operation to any UIView and specify the actual operation after clicking as needed. At this time, we can associate a gesture object and an operation block object to our UIView object. This task is divided into two parts. First, if needed, we need to create a gesture recognition object and use it and the block as associated objects. 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 objects for gesture recognition. If not, create and establish an association. At the same time, the incoming block object is connected to the specified key. Note the associated memory management strategy for the block object.

The gesture recognition object requires 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 operation when the click gesture is recognized.

From the above example, we can see that the associated objects are not complicated to use. It allows us to dynamically enhance the existing functions of the class. We can use this feature flexibly in actual coding.

Operation methods of member variables and attributes
Member variable operations include the following functions:

// Get member variable name

const char * ivar_getName (Ivar v);



// Get member variable type code

const char * ivar_getTypeEncoding (Ivar v);



// Get the offset of the member variable

ptrdiff_t ivar_getOffset (Ivar v);
● ivar_getOffset function. For instance variables of type id or other object types, you can call object_getIvar and object_setIvar to directly access member variables without using an offset.

Associated object
The associated object manipulation functions include the following:

// 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 associated objects

void objc_removeAssociatedObjects (id object);
The associated objects and related instances have been discussed previously, and are not repeated here.

Attributes
Attribute operation related functions include the following:

// Get the attribute name

const char * property_getName (objc_property_t property);



// Get the attribute description string

const char * property_getAttributes (objc_property_t property);



// Get the characteristics specified in the attribute

char * property_copyAttributeValue (objc_proper

ty_t property, const char * attributeName);



// get the list of attributes

objc_property_attribute_t * property_copyAttributeList (objc_property_t property, unsigned int * outCount);
● The property_copyAttributeValue function, the returned char * needs to be released by calling free () after use.

● The property_copyAttributeList function, the return value needs to be released by calling free () after use.

Examples
Assume a scenario where we get the same dictionary data from two different interfaces on the server, but these two interfaces are written by two people, and the same information is represented by different fields. When we receive the data, we can save it 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 interfaces A and B is as follows:

@ {@ "name1": "张三", @ "status1": @ "start"}



@ {@ "name2": "张三", @ "status2": @ "end"}
The usual method is to write two methods to convert separately, but if you can flexibly use Runtime, you can implement only one conversion method. To do this, we need to define a mapping dictionary (global variable) first.

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 different fields in the two dictionaries to the same attributes in MyObject. In this way, the conversion method can be processed 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: do processing for special data types

            NSString * attributeString = [NSString stringWithCString: property_getAttributes (property) encoding: NSUTF8StringEncoding];



            ...



            [self setValue: obj forKey: propertyKey];

        }

    }];

}
Of course, the premise of whether an attribute can be processed in the above way is that it supports KVC.

summary
In this chapter we discussed the content related to member variables and attributes in Runtime. Member variables and attributes are the data foundation of the class. The reasonable use of the related operations in Runtime allows us to handle the work related to the class data more flexibly.

Objective-C Runtime Runtime 2: 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.