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_getOffset
Functions, for typesid
Or an instance variable of another object typeobject_getIvar
andobject_setIvar
To 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_copyAttributeValue
Function, which returnschar *
Need to be called after usefree()
Release.property_copyAttributeList
Function 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 time
Animal
A subclass ofPanda
; - Then add Ivar to it dynamically:
_runtimeProperty
Corresponding Property:runtimeProperty
And the correspondingGetter/Setter
Methods:runtimeProperty``setRuntimeProperty
; - Then we traversed and printed
Panda
Ivar list and Property list; - And then create
Panda
An instance ofpanda
, and uses Property; - We ended up destroying it
panda
和Panda
.
Here are a few things to note:
- We can’t use
class_addIvar()
Function to add to an existing classIvar
And,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!