Chapter 11 Categories and Protocols

Categories
这个categories是Objective-C特有的语法,它是对已有类声明的扩展,其作用是将类中相关的方法模块化,就是将类中的方法划分成若干个类别,每个类别有个名目。

Chapter 11 Categories and Protocols_第1张图片

上图就是Fraction类中的一个类别MathOps,由于它是对原类的扩展,所以必须引进原来的类声明,即#import “Fraction.h”。
正因为引进了原来的类声明,编译器知道原来的类长成啥样子,所以此处不用写该类的父类。
你可以把categories中方法的定义与原来的类方法的定义写在同一个@implementation里面,你也可以分开写。后者你必须如下图这样写:
Chapter 11 Categories and Protocols_第2张图片

按照惯例用“类名+类别名.h”和“类名+类别名.m”来命名单独的categories头文件和源文件,也就是类别的方法定义单独写在一个文件里的那种形式。例如,MathOps类别所在的头文件就可以写成“Fraction+MathOps.h”,源文件可以写成“Fraction+MathOps.m”。
一般来讲如果把类别和原类放在一起,万一原类不允许被更动,那么类别也休想被更动,因为它们在同一个文件里面。如果你不想这样的话还是把它们分开写的好。
ClassExtensions
类别也可以是无名的,这种无名的类别叫做类扩展。
类扩展允许你通过增加实例变量和属性来扩展类,这是有名类别做不到的。
类扩展中方法的定义是在类的@implementation中定义的而不是单独的。
类扩展中的方法是私有的,说白了就是相当于C++中的private段,这个不同于带有减号的方法,因为那些是给对象用的,而这一段所说的是类本身要用到的。
这些方法之所以是私有的是因为它们没有在类的@interface中声明,但是如果客户要是知道某个方法的话同样可以使用,所以这个私有与C++中的私有相比起来封装性不好。
如果你想让某个方法只能通过别的方法访问,即变成私有的,那你可以把它的声明

写到.m源码文件中去。
Some Notes about Categories
类别中的方法能覆盖原类中的方法,但是这不是好的编程习惯,因为你再也不能用原来类的那个方法了。
如果你非要覆盖,最好写个子类。
不要在各类别中定义同一方法,因为编译器不知道哪个是哪个。
类别不仅能影响本类还能影响子类,因为所有子类都会继承类别的方法,不管那些子类能否用得着,这很危险。
类别可能会破坏你最初使用它们的目的,所以你要确保类别是为你的目的服务的。
Objective-C中的namespace是被程序代码和所有库共享的,所以object/category名称对必须是惟一的。
Protocols and Delegation
protocol,协议,一看到这个我就想到计算机网络里的协议了,但是此协议非彼协议。
Objective-C中的协议是指可以被类共享的一系列方法。
协议中的方法可以是毫不相关的,这些方法都是与某个名称相关联的。
协议中方法有些你必须实现,有些你可以选择实现。如果你实现了协议中所有必须被实现的方法,那这叫做与协议一致,或者接受协议。Objective-C允许你定义一个协议,这个协议里的方法要么都是可选的,要么都是必须要实现的。
定义一个协议的语法如下所示:

首先是要使用@protocol指令,后接该protocol的名字,里面的方法声明与@interface中的一样,@end结束此protocol。
接受协议意味着你要实现协议中所有必须被实现的方法,其语法如下:

在上图中AddressBook是你自己的类,NSCopying是你要接受的协议,你需要把它用尖括号括起来,跟在父类和本类后边。
当你接受多个协议的时候可以这样写:

一旦一个类接受了协议,它的子类也就自然而然地接受了协议,无论它需不需要。
父类接受的协议可以在子类中实现。
协议中可选的方法是用@optional表示出来的,如下图所示:
Chapter 11 Categories and Protocols_第3张图片

当然你也可以用@required命令把协议中那些必须被实现的方法标识出来。
如果你不实现这些方法,编译器也不会报错顶多是警告。
协议是一个与类无关的概念,任何类都可以去接受协议,所以有的时候你需要判断某对象是否接受了某协议,你可以使用conformsToProtocol:方法判断,如下图所示:

在这里currentObject消息的接收者@protocol (Drawing)是消息的内容,从语法层面来讲,前者是调用方。
检查协议中某方法是否被实现的写法如下所示:

@selector返回某方法的唯一标识,也可以理解为id,这有点像函数指针的意思。
你可以让编译器帮你检查某对象是否接受了某协议,如下图所示:


如果是静态类型的话,该对象没有接受该协议编译器就会发出警告。
如果是动态类型的话,编译器是不会发出警告的,因为它也不知道该对象到底有没有接受该协议,不过我想在运行期可能会发出一些警告或错误。
协议也是可以接受协议的,如下图所示:

Drawing3D协议就接受了Drawing协议。
category也可以接受协议,如下图所示:

如果你不想让别人知道你的类接受了某个protocol,那你可以让你的无名category,也就是类扩展,去接受这个协议,如下图所示:

和类名一样,protocol名也必须是惟一的。
感觉protocol有点像java里面的interface。
Delegation
delegation——委托。
delegation的思想是你知道你要做什么事情,但是这件事情你不想自己去做,你的关注点在于功能的组织上,至于具体的实现就交给相应的类去处理吧。这也是面向接口编程思想的反应,protocol就是一种delegation。
Informal Protocols
informal protocol其实是一个category,因为每个类都是从根类,即,最上层的类继承而来的,所以informal protocol其实是为根类定义的。
有时候informal protocol也被称为abstract protocol。
它其实没有什么语法上的作用,只不过这样做看起来比较工整有利于模块化组织。
声明abstract protocol的类并不实现它的方法,实现该abstract protocol的子类需要在他自己的@interface中再次声明这些方法,并在@implementation中去实现abstract protocol中的方法。编译器不对informal protocol提供任何帮助。
接受informal protocol的对象可以不实现所有方法,编译器对它的一致性检查只在运行时进行。但是formal protocol的一致性检查无论是在编译期还是运行期都是必须的。
@optional指令的目的是想代替informal protocol。
Composite Objects
这是一种设计思想而不是语言特性,关于这一点Effective C++里面讲过。

你可能感兴趣的:(Chapter 11 Categories and Protocols)