caregory 和 extension

caregory   (类别)  

不论一个类设计的有多完美,在需求的演绎中总会碰到无法预测的情况,可以动态的为已有的类添加新行为

一、caregate主要作用

1 >  为已知类添加方法

2 >  可以把类的实现部分放在几个不同的文件里,减少单个文件的体积;可以把不同功能组织到不同的Category中;可以由多个开发者共同完成一个类

二、Category实现原理

所有OC类和对象在runtime底层都是以结构体表示的,是category_t

typedef 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;  添加的所有属性

} category_t;

可以看出category可以添加实例方法、类方法、实现协议、添加属性、但不能添加实例变量。这里简单说一下实例变量、属性之间的关系

@interface MyViewController :UIViewControlle
{

  UIButton *yourButton;
   int count;
   id data;
}

@property (nonatomic, strong) UIButton *myButton;
@end

实例变量:由类定义的,除去基本数据类型  int、float,,,其他类型的变量都是实例变量

成员变量:代码中的变量、包括实例变量和基本变量类型,不需要和外界接触,默认的是protected,一般非子类都无法访问

属性:编译器自动将变量的setter和getter 方法的合成,可以用点语法来读取,可以为变量使用,可以与外界接触

实例变量 +  基本数据类型 =  成员变量

在{ }中声明的都是成员变量,所以youButton、count、data都是成员变量,实例变量是针对类而言的,成员变量用于类的内部,成员变量不会生成setter和getter方法,为了方便就有了属性,属性的好处是允许其他对象访问到该变量,因为属性的创建自动生成了setter和getter方法

如下:如果声明了实例变量就会报错

oc的运行时依赖于runtime,加载过程

       拿到编译器为我们准备的category的数组,将category的实例方法、协议、属性添加到类上,把类方法协议方法加到,metaclass上,(category的各种列表添加到类上会调用   addUnattachedCategoryForClass,但他只是一个映射,真正处理事情的是re'methodizeClass,对于添加类方法会调用 attachCategoryMethods方法,他只有把所有的Category实例拼成一个大的实例方法交给attachMethodList方法),然而Category的方法并没有替换原来的方法,会覆盖原来的方法,因为Category的方法被放到了新列表的前面,在运行时查找方法的时候是顺着方法列表的顺序查找的,只要查找到了对应的名字方法,就会调用

为什么Category中 不能添加实例变量?

1、前边说过,Category本身的定义中没有实例变量的数组,但在runtime中确实有一个函数:class_addIvar().用来给类添加实例变量,但是这个函数只能在构建一个雷的过程中调用,一旦类完成了定义,就不能再添加成员变量了,类在经过编译期之后就启动了runtime,就没有机会调用addIvar方法了,程序在运行时动态的构建类会调用objc_allocateClasspair之后,但在objc_registerClass之前才可以被调用,同样是没有机会。

2、一块区域内存包含了所有的成员变量和isa指针,因此在编译的时候就已经分配好了内存,所以动态的改变了成员变量就改变了这块内存的布局

那么如果一定要才Category中实现添加变量

OC是一门动态的语言,runtime中有两个函数objc_getAssoctatedObject / objc_setAssoctatdObject 来访问和生成关联对象,这两个方法可以让一个对象和另一个对象关联,也就是说一个对象保持对另一个对象的引用,并获取那个对象

定义一个属性,重写setter和getter方法

在setter和getter方法中返回    return  objc_getAssoctatedObject(self,name)    和  objc_setAssoctatedObject(self,nameKey,name,now)

extension  和  Category  比较

extension看起来像一个匿名的Category,但是extension和有名字的Category是两个不同的东西,extension在编译期决定,他就是类的一部分,在编译期将头文件中的interface和实现里边的implement一起形成一个完整的类,一般用来隐藏隐藏类的私有信息,必须要有一个类的源码才能添加,它伴随着这个类的产生而产生,消失而消失,因此他可以添加实例变量、属性、方法,但都是私有方法。

Category是在运行期决定的,他是无法添加实例变量的,在编译期对象的内存分布已经确定,如果添加实例变量会破坏类的内存布局。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值