1. category
category_t 结构体构成
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);
};
分析:
1 分类是一个包含对象方法,类方法,协议,属性等的结构体,因此,可以在分类中添加对象方法,类方法,协议等.
2 分类是将结构体中的方法列表等拷贝到原类对象的方法列表中.
3 分类中可以添加属性,但是并不会自动生成成员变量及set、get方法,因为 category_t 结构体不存在成员变量列表.
4 成员变量是存放在实例对象里的,并在编译阶段就已经决定好了,而分类是在运行时才去加载的.我们无法在程序运行时将分类的成员变量添加到实例对象的结构体中,因此分类中不能添加成员变量.
2. Extension
Extension 是一种特殊的分类.类扩展与分类相比只少了分类的名称,所以称之为“匿名分类”.一般用来扩展私有属性和方法.
3. 分类和扩展之间的区别
- 分类不可以直接添加属性,但可以通过 runtime 添加,扩展可以直接添加属性.
- 如果分类中有和原有类同名的方法, 会优先调用分类中的方法,也就是说会忽略原有类的方法.所以同名方法调用的优先级为: 分类 > 本类 > 父类.
- 如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定,编译器会执行最后一个参与编译的分类中的方法(可以在 buildPhases -> Compile Sources 里面调整编译顺序).
- Extension 只能用于自身类,而不能用于子类或者其他地方.
- Extension 中声明的方法必须要实现,否则编译器警告.Category 不会.这是因为 Extension 是编译阶段被添加到类中,Category 是运行时被添加到类中.
4.Category 添加属性
方案一
在.h中
@property(nonatomic,copy) NSString *name;
在.m中
static NSString *_name;
-(void)setName:(NSString *)name{
_name = name;
}
-(NSString *)name{
return _name;
}
方案二
在.h中
@property(nonatomic,copy)NSString *age;
在.m中
-(void)setAge:(NSString *)age{
//参数一:给那个对象添加属性
//参数二:属性名
//参数三:关联的值,也就是set方法存入值给属性去保存
//策略
objc_setAssociatedObject(self, @"age",age, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)age{
return objc_getAssociatedObject(self, @"age");
}
分类关联对象:关联对象并不是存储在被关联对象本身内存中,而是存储在全局的统一的一个 AssociationsManager 中.如果设置关联对象为nil,就相当于是移除关联对象.
补充: load 和 initialize 的区别
- load 方法是在 pre-main 阶段装载类信息的时候就调用;initialize 是在类第一次接收到消息的时候调用
- load 方法的调用顺序为父类 --> 子类 --> 分类;initialize 调用顺序为父类 --> 子类或者分类,且父类 initialize 只会调用一次,分类的 initialize 会覆盖子类的 initialize.
- load 方法是通过 isa 指针找到对应的方法与实现;initialize 方法是通过 runtime 的消息转发机制调用.
- load 方法一般用于方法交换;initialize 方法一般用于初始化全局变量或静态变量.
- load方法不可以继承; initialize 可以.
网友评论