今天要做的事有很多呢
Category是Objective-C 2.0之后添加的语言特性,分类、类别其实都是指的Category。Category的主要作用是为已经存在的类添加方法。
Objective-C 中的 Category 就是对装饰模式的一种具体实现。它的主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法。
分类优点
声明私有方法
分解体积庞大的类文件
把Framework私有方法公开
模拟多继承(另外可以模拟多继承的还有protocol)
Category源码:
Category 是表示一个指向分类的结构体的指针,其定义如下:
typedef struct objc_category *Category;
struct objc_category {
char *category_name OBJC2_UNAVAILABLE; // 分类名
char *class_name OBJC2_UNAVAILABLE; // 分类所属的类名
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE; // 实例方法列表
struct objc_method_list *class_methods OBJC2_UNAVAILABLE; // 类方法列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 分类所实现的协议列表
}
结构体主要包含了分类定义的实例方法与类方法,其中instance_methods 列表是 objc_class 中方法列表的一个子集,而class_methods列表是元类方法列表的一个子集。
实现原理
1.我们不主动引入 Category 的头文件,Category 中的方法都会被添加进主类中。我们可以通过 - performSelector: 等方式对 Category 中的相应方法进行调用:
a)将 Category 和它的主类(或元类)注册到哈希表中;
b)如果主类(或元类)已实现,那么重建它的方法列表。
2.在这里分了两种情况进行处理:
a)Category 中的实例方法和属性被整合到主类中;
b)类方法则被整合到元类中
c)对协议的处理比较特殊,Category 中的协议被同时整合到了主类和元类中。
3.最终都是通过调用 staticvoid remethodizeClass(Class cls) 函数来重新整理类的数据的。
分类特点
1.分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性 ;
2.分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量,会编译通过,但是引用变量会报错;
3.如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法,同名方法调用的优先级为 分类 > 本类 > 父类;
4.如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
5.运行时决议
6.同名分类方法生效取决于编译顺序
7.名字相同的分类会引起编译报错
在分类中,给分类添加成员变量实际上是添加属性:
示例代码
import <objc/runtime.h>
/* ---------------.h---------------*/
@interface NSString (url)
@property (nonatomic, retain) NSString *url;
@end
/* ---------------.m---------------*/
static char imageURLKey;
@implementation NSString (url)
-
(void)setUrl:(NSString *)url
{
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} -
(NSString *)url
{
return objc_getAssociatedObject(self, &imageURLKey);
}
@end
objc_getAssociatedObject
这个函数先根据对象地址在 AssociationsHashMap 中查找其对应的 ObjectAssociationMap 对象,如果能找到则进一步根据 key 在 ObjectAssociationMap 对象中查找这个 key 所对应的关联结构 ObjcAssociation ,如果能找到则返回 ObjcAssociation 对象的 value 值,否则返回 nil;
objc_getAssociatedObject有两个参数,第一个参数为从该object中获取关联对象,第二个参数为想要获取关联对象的key;
/**
- Returns the value associated with a given object for a given key.
- @param object The source object for the association.
- @param key The key for the association.
- @return The value associated with the key \e key for \e object.
- @see objc_setAssociatedObject
*/
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
objc_setAssociatedObject
参数说明:
object和key同于objc_getAssociatedObject;
value:需要和object建立关联引用对象的value;
policy:关联策略,等同于给property添加关键字
/**
- Sets an associated value for a given object using a given key and association policy.
- @param object The source object for the association.
- @param key The key for the association.
- @param value The value to associate with the key key for object. Pass nil to clear an existing association.
- @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
- @see objc_setAssociatedObject
- @see objc_removeAssociatedObjects
*/
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
与分类相似的还有一个扩展:
扩展
声明私有属性
声明私有方法
声明私有成员变量
编译时决议
只以声明存在,寄生于宿主类.m中
不能为系统类添加扩展
类扩展优缺点分析
① 类扩展的属性和方法都是私有的,也可以定义在.h中,这样就是共有的,类扩展中的方法是一定要实现的方法。Category没有这个限制。
分类、扩展区别
category、extension异同点分析
1、分类(category)
① category只能添加“方法”,不能添加成员变量。
② 分类中可以访问原来类中的成员变量,但是只能访问@protect和@public属性。
③ 添加方法加上前缀,添加方法会覆盖父类的同名方法,可以防止意外覆盖,也防止被别人覆盖。
④ 分类中添加的成员变量,要通过getter、setter方法进行添加。
类扩展(extension)
① 类扩展的属性和方法都是私有的,也可以定义在.h中,这样就是共有的,类扩展中的方法是一定要实现的方法。Category没有这个限制。
网友评论