分类,类扩展理解:

一:分类(类别):

OC中Category是Objective-C2.0之后添加的语言特性,它称为分类,或者类别;

分类的主要作用,是为已经存在的类添加方法。(不改变已经存在类的前提下,为类动态的添加一些方法)。

 

二:分类的源码解析:

struct objc_category {

    char * _Nonnull category_name                            OBJC2_UNAVAILABLE;

    char * _Nonnull class_name                               OBJC2_UNAVAILABLE;

    struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE;

    struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE;

    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;

}                                                            OBJC2_UNAVAILABLE;

其中:

category_name:分类名

class_name:分类所属类名

instance_methods:分类添加的对象方法链表

class_methods:分类添加的类方法链表

protocols:分类实现的协议链表

1):实现原理:(运行时,系统会整合分类中的方法,协议到所属类中

当开发者创建category时,在运行时,系统会自动的把分类中实现的方法,整合到分类所属类,元类的方法列表中。

a):对象方法会整合到类的方法链表中;类方法会整合到元类的方法链表中;

         (方法整合的原则:将分类中的方法插入到类的方法列表之前,这样保证了分类中的方法优先调用。所以,当分类重写了类中的方法时,方法整合并不是分类中的方法覆盖类中的方法,而是分类中的方法插入到类的方法链表首端,以到达分类方法先于类方法调用目的)

b):分类中的协议比较特殊,会同时整合到类,元类中的协议链表中。

c):最终,系统均会通过remethodizeClass函数,来重建类,元类中的方法链表。

注意:我们并不需要主动引入分类文件,可以使用performSelector来调用分类中的方法

2):分类特点:

a):分类结构体中,没有对应的成员变量的链表,所以原则上分类中只能添加方法,并不能添加属性。(实际上,我们可以通过runtime,添加属性)

b):分类的.h文件中,可以使用@property声明属性,但实际上,系统并未实现该属性对应的setter,getter方法。(编译时可以通过,但使用该属性时,系统会抛出异常)

c):当分类与类中出现同名方法时(分类重写了类的方法),系统会优先调用分类中的方法。也就是说,同名方法调用顺序为:分类>类>父类。(由load加载机制我们知道,父类先于子类加载,类先于分类加载;因此,类先创建方法链表,分类后创建方法链表,我们把分类的方法链表整合到类的方法链表中去时,新添加的方法直接插入到类的方法链表的首端,所以,同名方法分类先于类执行)

d):如果多个分类中同时存在同名方法时,则系统执行最后编译的分类中的同名方法。(系统编译顺序由Build Phases中的Compile Sources列表给出)

 

三:分类的使用场景

1):创建私有变量(原则上不支持,但可以通过runtime为属性动态的添加setter,getter方法)

objc_setAssociatedObject:设置关联属性(policy,等同于给@property添加关键字)

objc_getAssociatedObject:获取关联属性

objc_removeAssociatedObjects:取消关联属性

使用如下:

.h文件中声明属性:@property (nonatomic, copy)NSString *btnName;

.m文件中设置setter,getter方法:

static char kUIButton_BtnName_Key;

- (void)setBtnName:(NSString *)btnName {

    objc_setAssociatedObject(self, &kUIButton_BtnName_Key, btnName, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

- (NSString *)btnName {

    return objc_getAssociatedObject(self, &kUIButton_BtnName_Key);

}

注意:

a):关联对象是由AssociationManager管理,并在AssociationHashMap存储的;

b):所有类的关联对象均是存储在一个全局容器AssociationHashMap中,它与类无关,由系统维持。

 

2):分解体积庞大的类文件(将同一业务的方法,整合到一个分类中)

3):模拟多重继承(一个对象,实现不同类(分类)的方法)

 

四:类扩展:

格式:(.m文件中)

@interface ViewController ()

   ... 可以声明私有属性,私有方法,私有成员变量

@end

注意:类扩展由编译期间决定(类扩展中的成员变量,方法在编译期间已经添加到类中)

 

五:分类与类扩展的区别:

1):添加成员变量,方法的区别:

分类原则上只能添加方法,不能添加成员变量(添加成员变量,也是通过runtime来手动实现setter,getter方法);

类扩展既能够添加成员变量,也能够添加方法(.h文件中的类扩展,添加的成员变量与方法是公开的;.m文件中的类扩展,添加的成员变量与方法是私有的)

2):是否实现方法的区别:

分类中的方法未实现时,编译期间不会报错,运行期间添加相应的实现即可;

类扩展中的方法未实现时,编译时会报错。

注意:类扩展中添加的成员变量及方法,是在编译时,添加到类中;分类中的方法,是在运行时时添加到类中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值