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:

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

The output is:

    1. 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.

Underlying 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:

  1. typedef struct OBJC_IVAR *ivar;
  2. struct Objc_ivar {
  3. Char *ivar_name objc2_unavailable; //variable name
  4. Char *ivar_type objc2_unavailable; //Variable type
  5. int Ivar_offset objc2_unavailable; //Base address offset byte
  6. #ifdef __lp64__
  7. int space objc2_unavailable;
  8. #endif
  9. }

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:

    1. 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:

    1. typedef struct {
    2. Const Char *name; //attribute name
    3. Const Char *value; //attribute value
    4. } 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:

    1. Objc_association_assign
    2. Objc_association_retain_nonatomic
    3. Objc_association_copy_nonatomic
    4. Objc_association_retain
    5. Objc_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:

    1. static char MyKey;
    2. 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.

    1. 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:

  1. -(void) Settapactionwithblock: (void (^) (Void)) block
  2. {
  3. UITapGestureRecognizer *gesture = Objc_getassociatedobject (self, &kdtactionhandlertapgesturekey);
  4. if (!gesture)
  5. {
  6. gesture = [[UITapGestureRecognizer alloc] initwithtarget:self action: @selector (__handleactionfortapgesture:)];
  7. [Self addgesturerecognizer:gesture];
  8. Objc_setassociatedobject (self, &kdtactionhandlertapgesturekey, gesture, objc_association_retain);
  9. }
  10. Objc_setassociatedobject (self, &kdtactionhandlertapblockkey, block, objc_association_copy);
  11. }

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:

  1. -(void) __handleactionfortapgesture: (UITapGestureRecognizer *) gesture
  2. {
  3. if (gesture.state = = uigesturerecognizerstaterecognized)
  4. {
  5. void (^action) (void) = Objc_getassociatedobject (self, &kdtactionhandlertapblockkey);
  6. if (action)
  7. {
  8. Action ();
  9. }
  10. }
  11. }

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.

How to manipulate member variables and properties

Member variables

The member variable operation contains the following functions:

    1. Get member Variable name
    2. Const char * Ivar_getname (Ivar v);
    3. Get member Variable type encoding
    4. Const char * ivar_gettypeencoding (Ivar v);
    5. Gets the offset of the member variable
    6. 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:

    1. Setting Association objects
    2. void Objc_setassociatedobject (ID object, const void *key, id value, Objc_associationpolicy policy);
    3. Get Association Object
    4. ID objc_getassociatedobject (ID object, const void *key);
    5. Remove an associated object
    6. 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:

  1. Get Property name
  2. Const char * PROPERTY_GETNAME (objc_property_t property);
  3. Get Property Attribute Description string
  4. Const char * property_getattributes (objc_property_t property);
  5. Gets the attribute specified in the property
  6. char * Property_copyattributevalue (objc_property_t property, const char *attributename);
  7. Gets the attribute list for the property
  8. 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:

    1. @Interface Myobject:nsobject
    2. @property (nonatomic, copy) NSString * name;
    3. @property (nonatomic, copy) NSString * status;
    4. @end

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

    1. @{@"name1": "Zhang San", @"Status1": @"Start"}
    2. @{@"name2": "Zhang San", @"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)

  1. static nsmutabledictionary *map = nil;
  2. @implementation MyObject
  3. + (void) load
  4. {
  5. Map = [Nsmutabledictionary dictionary];
  6. map[@"name1"] = @"name";
  7. map[@"Status1"] = @"status";
  8. map[@"name2"] = @"name";
  9. map[@"Status2"] = @"status";
  10. }
  11. @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:

  1. -(void) Setdatawithdic: (Nsdictionary *) dic
  2. {
  3. [DiC enumeratekeysandobjectsusingblock:^ (nsstring *key, id obj, BOOL *stop) {
  4. NSString *propertykey = [self propertyforkey:key];
  5. if (propertykey)
  6. {
  7. objc_property_t property = Class_getproperty ([Self class], [PropertyKey utf8string]);
  8. //TODO: Processing for special data types
  9. NSString *attributestring = [NSString stringwithcstring:property_getattributes (property) Encoding: Nsutf8stringencoding];
  10. ...
  11. [Self setvalue:obj forkey:propertykey];
  12. }
  13. }];
  14. }

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.

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.