类别是在运行时决定的,在运运行时才会分配相应的内存空间,在就决定了在编译期是不能给某个类增加属性,否则会影响内存布局,从而导致crash ,若想给某个类增加一个属性,需要在运行时添加,首先先介绍下类别的结构
这个结构体理念包含这个类别的名字,实例方法,类方法,协议名,和实例属性
正如我们所知的那样,当我们重写类的一个方法以后,会覆盖原来类的方法,它为什么会覆盖原来类的方法呢,我们先来看一下当调用一个方法的时候是怎么运行的
在这里面我们可以看到,是先根据isa 指针找到该类,然后在该类的方法列表里面找到该方法的实现,当重写一个类的方法后,它会将重写的方法,放在方法列表的第一位,当第一次找到该方法的时候就不会在查找,就会执行重写的方法实现,如果我们想执行原来的方法实现就可以跳过方法列表前面的方法实现,执行最后一个该方法的实现就可以了
上面的printName为重写的方法名,获取最后一个类名和方法实现,这样就可以调用被重写的方法实现。
前面提到不可以在编译期给类增加属性,那可以在运行期动态的给某个类添加属性,可以调用message API来实现
我们对某个类得分类中增加一个name 属性,重写name 的set 和get方法就可以为其添加属性了,此外给大家奉上我做的一个相关的demo 地址 类别的方法覆盖和添加属性 此外在此谢谢美团技术团队的技术分享 美团类别分享
1、分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。所以<原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性>
为什么在分类中声明属性时,运行不会出错呢?
既然分类不让添加属性,那为什么我写了@property仍然还以编译通过呢?
我们知道在一个类中用@property声明属性,编译器会自动帮我们生成_成员变量和setter/getter,但分类的指针结构体中,根本没有属性列表。所以在分类中用@property声明属性,既无法生成_成员变量也无法生成setter/getter。
因此结论是:我们可以用@property声明属性,编译和运行都会通过,只要不使用程序也不会崩溃。但如果调用了_成员变量和setter/getter方法,报错就 在所难免 了。
既然报错的根本原因是使用了系统没有生成的setter/getter方法,可不可以在手动添加setter/getter来避免崩溃,完成调用呢?
其实是可以的。由于OC是动态语言,方法真正的实现是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法。那具体怎么实现呢?
按照这个思路,我们通过运行时手动添加这个方法。
#import <objc/runtime.h>
static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey" //定义一个key值
@implementation Programmer (Category)
//运行时实现setter方法
- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {
objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY)
}
//运行时实现getter方法
- (NSString *)nameWithSetterGetter {
return objc_getAssociatedObject(self, &nameWithSetterGetterKey)
}
@end
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)