3. 分类,类扩展

2020-06-24  本文已影响0人  如果大雨落下

分类

作用: 声明私有方法,分解体积大的类文件,把framework的私有方法公开
Category源码:

Category
Category 是表示一个指向分类的结构体的指针,其定义如下:
typedef struct objc_category *Category;
struct objc_category {
  const char *name                          OBJC2_UNAVAILABLE; // 分类名
  Struct _class_t *cls;                             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; // 分类所实现的协议列表
  struct objc_properties_list *properties         OBJC2_UNAVAILABLE; // 属性列表

}

- 在编译的时候,会将每一个分类都转换成一个category_t的结构体,里面会存放原类的名称,实例方法列表,类方法列表,协议列表,还有属性列表

- 在程序运行的时候,会将所有分类的方法,属性,协议等东西添加到原类里面

- 添加顺序,是先将原类的存储数组通过memmove往后面移动,然后再将添加的分类信息copy过来,所以分类的信息会放在数组的前面,这也是为什么会优先调用分类方法的原因,如果分类里面有同样的方法,取决于分类的编译顺序,越后面编译的分类方法,越放在前面,越先被调用,这个里面的方法并不是被覆盖,其他分类方法也可以调用,只是执行顺序的问题

3. 分类,类扩展

注意:

  1. 分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。所以< 原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性> ,只能通过关联对象(objc_setAssociatedObject)来模拟实现成员变量,但其实质是关联内容,所有对象的关联内容都放在同一个全局容器哈希表中:AssociationsHashMap,由AssociationsManager统一管理。
  2. 分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量(编译时会报警告);
  3. 可以在分类中访问原有类中.h中的属性;
  4. 如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法。所以同名方法调用的优先级为 分类 > 本类 > 父类。因此在开发中尽量不要覆盖原有类;
  5. 如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
  6. 一个类中用@property声明属性,编译器会自动帮我们生成成员变量和setter/getter,但分类的指针结构体中,根本没有属性列表。所以在分类中用@property声明属性,既无法生成成员变量也无法生成setter/getter。
    因此结论是:我们可以用@property声明属性,编译和运行都会通过,只要不使用程序也不会崩溃。但如果调用了_成员变量和setter/getter方法,报错就在所难免了。

类扩展(Class Extension)

Extension是Category的一个特例。类扩展与分类相比只少了分类的名称,所以称之为“匿名分类”。

就是.m 文件中声名的

@interface XXX ()
    //私有属性
    //私有方法(如果不实现,编译时会报警,Method definition for 'XXX' not found)
@end

分类与类扩展的区别:

分类在运行时加入到原类中,类扩展在编译的时候就加入了原类

上一篇下一篇

猜你喜欢

热点阅读