Exploration of the Reasons why iOS Classification Can't Add Attributes

Keywords: Attribute iOS

Recently, when communicating with people, a question was raised that attributes could not be added to iOS classifications. Here we discuss the reasons why we can't add it and the ways to add it.
First, create a person class with the following code:

XGPerson.h

#import <Foundation/Foundation.h>

@interface XGPerson : NSObject
/// Age
@property (nonatomic, copy) NSString *age;
/// Gender
@property (nonatomic, copy) NSString *sex;

- (void)text1;

@end

XGPerson.m

#import "XGPerson.h"

@implementation XGPerson

- (void)text1 {
    NSLog(@"%s",__func__);
}

- (void)text2 {
    NSLog(@"%s",__func__);
}
@end

The member variables, attributes and methods of this class are captured and printed in the controller. The code is as follows:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // Get member variables
    unsigned int ivarCount = 0;
    Ivar *ivars = class_copyIvarList([XGPerson class], &ivarCount);
    for (int i = 0; i < ivarCount; i++) {
        Ivar ivar = ivars[i];
        NSLog(@"The first%d Membership variables:%s",i,ivar_getName(ivar));
    }
    free(ivars);
    // get attribute
    unsigned int propertyCount = 0;
    objc_property_t *propertyList = class_copyPropertyList([XGPerson class], &propertyCount);
    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = propertyList[i];
        NSLog(@"The first%d Attributes:%s",i,property_getName(property));
    }


    // Get a list of methods
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList([XGPerson class], &methodCount);
    for (int i = 0; i < methodCount; i++) {
        Method method = methods[i];

        NSLog(@"The first%d Methods:%s",i, sel_getName(method_getName(method)));
    }

}

At this time, the console output is as follows:

png without classification


What we need to mention here is that when @property is used, the system will automatically generate the setter and getter methods with "" member variables and that variable. In other words, attributes are equivalent to a member variable plus getter and setter methods. So what would it look like to use @property in a classification? Here's how to create a classification:
XGPerson+height.h

#import "XGPerson.h"

@interface XGPerson (height)

@property (nonatomic, copy) NSString *height;

@end

XGPerson+height.m

#import "XGPerson+height.h"

#import <objc/runtime.h>

@implementation XGPerson (height)


@end

If you declare height only in the. h file as above, two warnings will appear in the. m file, meaning that setter and getter methods are not implemented.

Warning. png

At this time, the touchesBegan method is executed in the controller, and the console output is as follows:

Classified unrealized access method.png


As you can see, there is no member variable with "" added to the person class at this time, nor the setter and getter methods are implemented, but only the height attribute is added to the list of attributes. At this time, if self.height is called in the controller, the program runs with an error, indicating that the method can not be found. Implement two methods in person classification:
XGPerson+height.m

#import "XGPerson+height.h"

#import <objc/runtime.h>

@implementation XGPerson (height)

 - (NSString *)height {

 }

 - (void)setHeight:(NSString *)height {

 }

@end

At this time, the touchesBegan method is executed in the controller, and the console output is as follows:

Classified access method.png

You can see that even if setter and getter methods are implemented, no member variables with "" are added, that is to say, member variables starting with the underline can not be accessed directly in setter and getter methods, because the system does not add member variables starting with "" when declaring attributes with @property in classification. . The runtime Association object can be used to achieve the purpose of adding at this time. The sample code is as follows:
XGPerson+height.m

#import "XGPerson+height.h"

#import <objc/runtime.h>

@implementation XGPerson (height)



 - (NSString *)height {
 return objc_getAssociatedObject(self, @"height");
 }


 - (void)setHeight:(NSString *)height {
 objc_setAssociatedObject(self, @"height", height, OBJC_ASSOCIATION_COPY_NONATOMIC);
 }

@end

Of course, other attributes of this class can also be accessed in setter and getter methods, such as adding x and Y attributes to the UIView classification, which can directly return self.frame.origin.x and self.frame.origin.y.

summary

In the classification, @property is used to declare attributes, which is added to the list of attributes of the class and the setter and getter methods are declared, but the corresponding member variables are not generated and the setter and getter methods are not implemented. So classification cannot add attributes. But after using @property to declare attributes in classification, setter and getter methods are implemented, so that the attributes can be assigned and valued by point grammar normally outside this class. That is to say, after using @property to declare attributes in a class and implementing setter and getter methods, you can think of adding attributes to this class.

Posted by thisisnuts123 on Tue, 02 Jul 2019 15:08:53 -0700