ToB企服应用市场:ToB评测及商务社交产业平台
标题:
【iOS】——分类,扩展以及关联对象
[打印本页]
作者:
用多少眼泪才能让你相信
时间:
2024-8-18 20:45
标题:
【iOS】——分类,扩展以及关联对象
1. 分类(Category)和扩展(Extension)
1) 分类(运行期)
分类就是为已经存在的类,在运行时添加新的方法的一种机制。
分类可以添加协议,类方法,实例方法和属性,不能添加实例变量。
添加的属性就不会生成成员变量,也不会生成setter/getter方法,必要手动添加setter/getter方法。
2)扩展(编译期)
扩展和分类很像,扩展只有声明部分,扩展中的定义的方法必要在类的实现部分去实现。
可以定义协议,类方法,实例方法,属性和实例变量,在编译期将此中的定义的数据加到该类的数据类表中。假如不实现此中的方法,就会报错。
由于系统的类的是实现部分不对用户开放,以是不能给系统的类添加扩展。
3)区别
扩展在编译期决定,是类的一部分,和类的声明部分和实现部分共同组成类,陪同着类的产生而产生,消亡而消亡。扩展也可以用来潜伏类的私有部分。
分类是在运行期决议的,扩展可以添加实例变量,分类不能添加实例变量,原因是在运行时,对象的内存结构就已经确定好了,假如添加实例变量,会粉碎类的内存结构。
2. 分类的实质
1)分类原理
typedef struct category_t *Category;
struct category_t {
const char *name; // 分类名
classref_t cls; // 类
struct method_list_t *instanceMethods; // 实例方法
struct method_list_t *classMethods; // 类方法
struct protocol_list_t *protocols; // 协议
struct property_list_t *instanceProperties; // 实例属性
// Fields below this point are not always present on disk.
struct property_list_t *_classProperties; // 类属性
method_list_t *methodsForMeta(bool isMeta) {
if (isMeta) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
复制代码
发现里面存在实例方法列表,类方法列表,实例属性列表与类属性列表。
2)分类的加载流程
在编译阶段将分类中的方法、属性等编译到一个数据结构category_t。
将分类中的方法、属性等归并到一个大数组中,反面参加编译的分类会在数组的前面。
将归并后的分类数据(方法、属性、协议),插入到类原来数据的前面。
也就是说当分类中的方法与原始类中的方法重名时,会先去调用分类中实现的方法。
2. 关联对象
通过关联对象给分类添加属性
动态添加
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
复制代码
参数一:
id object : 给哪个对象添加属性,这里要给自己添加属性,用self。
参数二:
void * == id key : key值,根据key获取关联对象的属性的值,在objc_getAssociatedObject中通过次key得到属性的值并返回。
** 参数三:**id value : 关联的值,也就是set方法传入的值给属性去生存。
参数四:
objc_AssociationPolicy policy : 策略,属性以什么形式生存。
取值
objc_getAssociatedObject(id object, const void *key);
复制代码
参数一:id object : 获取哪个对象里面的关联的属性。
参数二:void * == id key : 什么属性,与objc_setAssociatedObject中的key相对应,即通过key值取出valu
移除关联对象
- (void)removeAssociatedObjects
{
// 移除关联对象
objc_removeAssociatedObjects(self);
}
复制代码
应用
//分类.h文件
#import "LGPerson.h"
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson (cat)
@property (nonatomic, copy) NSString *lg_nickname;
@property (nonatomic, copy) NSString *name;
@end
NS_ASSUME_NONNULL_END
//分类.m文件
#import "LGPerson+cat.h"
#import <objc/runtime.h>
@implementation LGPerson (cat)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *) name {
return objc_getAssociatedObject(self, _cmd);
}
@end
//main文件
#import <Foundation/Foundation.h>
#import "LGPerson+cat.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
LGPerson *t = [[LGPerson alloc] init];
t.name = @"1";
NSLog(@"%@", t.name);
}
return 0;
}
复制代码
运行结果:
总结:
分类中没有成员列表,因此不能添加成员变量。但是有属性列表,可以添加属性的声明,但是不会合成set与get方法,假如要利用分类中的属性,必要利用关联对象。
分类在运行的时间被整合到类中,扩展在编译的时间被整合到类中,因此分类中的方法不实现不会报错,扩展就会报错。
扩展用于声明私有属性与方法。
分类中的方法和类中的方法重名,分类中的方法会取代类中的方法。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4