Category

Posted by on January 20, 2019

Category (分类)

Category 的介绍

分类可以理解成是对一个已有类的功能进行扩展,但是分类主要是针对源码未知的类,一般是对系统的一些常用类进行扩展。如 NSString,Button,Label 等等,简单来说类别是一种为现有的类添加新方法的方式,让这个类能够适应不不同情况的需求。利用 OC 的动态运行时分配机制,分类提供了一种比继承更为简洁的方法来对类进行扩展,无需创建对象类的子类就能为现有的类添加新方法,可以为任何已经存在的类添加方法,包括那些没有源代码的类,如系统框架类 Foundation,UIKit 等等。

Category 的创建

Xcode 10 中添加方法如下: IMAGE

图1

下图中的 File 填写分类名,File Type 填写 OC 文件的类型选择 Category 就是分类的类型,Class 就你需要拓展的类的类名 IMAGE

图2

分类的作用

  • 对系统提供的框架类进行扩展,但由于没有源码,不可以修改。
  • 提供对类的私有方法访问权限:在你访问其他类的私有方法时编译器报错,这时使用分类在分裂中声明这些方法(不必提供方法实现),编译器就不会再产生警告。 举个例子: ``` //A.m
  • (void)test{ //自己定义就行,为了更明显的看到可以直接用 NSLog //NSLog(@”test”); } //A+CategoryA.h
  • (void)test; ```

分类的局限性

  • 分类只能增加方法,不能增加成员变量,但是可以通过运行时来给分类添加属性(@property) 由于分类中的添加了属性之后是没有实例变量的,因为之前编译时的内存已经规定好了,所以现在是无法添加的,如果需要添加就需要使用另一个机制 objc_AssociatedObject 将对象的键值对应,这样在运行时就方便查找了。并且在分类中如果引入了一个 @property 的话就一定需要自己实现它的 get 和 set 方法,对 objc_AssociatedObject 不熟悉的朋友建议先查看一下 API 然后再看代码。 IMAGE

    • 1.源对象,
    • 2.关联时的用来标记是哪一个属性的 key(因为你可能要添加很多属性),
    • 3.关联的对象
    • 4.一个关联策略。
  • 如果分类和原来类出现同名的方法, 优先调用分类中的方法,原来类中的方法会被忽略,方法调用的优先级 (从高到低) 分类 (最后参与编译的分类优先级更高) ,只要有分类就优先调用分类,不考虑与主类的编译顺序。

Extension

Extension 的介绍

Extension 是 Category 的一个特例经常被称作匿名分类,作用主要是为一个类增加私有方法,属性或成员变量,并且新添加的方法一定要予以实现,当然你可以不实现,但是会有 warning (Category 没有这个限制)。

Extension 的实现

  • 第一种方法 通过 Extension 来实现方法的私有, Extension 的头文件独立。但是这种方法不能实现真正的方法私有,当在别的文件中引入延展的头文件,那么在这个文件中定义的对象就可以直接调用在 Extension 中定义所谓私有的方法,并且一般而言我们都是将私有属性放在 Extension 当中。

  • 第二种实现 Extension 的方式 Extension 没有独立的头文件,直接就在类的实现文件 .m 中声明和实现延展,这种方法可以很好的实现方法的私有,因为在 OC 中是不能引入 .m 的文件的,只能是 .h 文件,但是在 OC 中是并不存在 100% 的私有这么一说的,这个咱们后面说。

  • 第三种实现方法 私有的方法是在 .m 文件中的 @implementation中 直接实现,但是在类的 @interface 中没有声明的方法,这样也可以很好的实现方法的私有,日常开发中经常使用。

inheritance

继承的介绍

如果学过 OOP (面向对象) 编程,那么对继承的这个概念肯定就不会陌生,继承我们一般是使用在对抽象出来的模型拥有相同的属性的时候,比如人拥有五官、两只手、两条腿,那么男人就可以继承人这个抽象模型,同理女人也可以,继承的过程中我们可以在子类当中对父类当中的方法进行重载或者覆盖,并且通过子类的继承,我们是可以进行拓展类的实例变量,以及属性,但是一般通过不断地继承会让我们的类变得臃肿,而往往优秀的代码是呈模块的形式的,因此最好不要有太多层的继承关系。

Category 和 Extension 的区别

常见的区别

  1. 形式上看:Extension 是匿名的 Category。
  2. Extension 中声明的方法需要在 implementation 中实现(可以不实现但是会报错,但是你可以不声明直接在 @implementation 文件中实现),而 Category 对实现不做强制要求。
  3. Extension 可以添加属性、成员变量,而 Category 一般不可以(可以添加属性但是要对键值绑定否则没有实例变量可以操作)。

虽然有人说 Extension 是一个特殊的 Category,也有人将 Extension 叫做匿名分类,但是其实两者差别很大。

Extension 的执行机制

  1. 在编译器决议,是类的一部分,在编译器和头文件的 @interface 和实现文件里的 @implement 一起形成了一个完整的类。
  2. 伴随着类的产生而产生,也随着类的消失而消失。
  3. Extension 一般用来隐藏类的私有消息,你必须有一个类的源码才能添加一个类的 Extension,所以对于系统一些类,如 NSString,就无法添加类扩展

Category 的执行机制

  1. 是运行时 (runtime) 决定的。
  2. 类的扩展可以添加实例变量,分类一般不能添加实例变量。原因:在运行时 (runtime),对象的内存布局已经确定,如果添加实例变量会破坏类的内部布局,这对编译性语言是灾难性的。