黑马程序员——Objective-C程序设计(第4版)学习笔记之11-分类和协议——黑马 IOS 技术博客

来源:互联网 发布:能朗读pdf的软件 编辑:程序博客网 时间:2024/04/19 10:31

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

这部分的内容呢,算是Objective-C比较有特色的章节。

简单说,分类呢有点类似抽象方法在抽象类中(C++或者Java里的那个抽象类概念)。协议类似接口(Java语言那个接口)。但是不能完全类比啊,只是说有些像,可以对比着来理解。

简单说:

分类定义:

@interface Fraction (MathOps)

-(Fraction *) add: (Fraction *) f;

@end


分类使用:

按方法走吧。别的就不啰嗦了。


协议定义:

@protocol NSCoping

- (id) copyWithZone: (NSZone *) zone;

@end

@protocol Drawing

-(void) paint;

@required

-(void) erase;

@optional

-(void) outline;

@end


协议使用:

@interface AddressBook:NSObject <NSCoping>


分类:

分类提供了一种简单的方式,用它可以将类的定义模块化到相关方法的组或分类中。它还提供了扩展现有类定义的简便方式,并且不必访问类的源代码,也不需要创建子类。

#import "Fraction.h"

@interface Fraction (MathOps)

-(Fraction *) add: (Fraction *) f;

-(Fraction *) mul: (Fraction *) f;

-(Fraction *) sub: (Fraction *) f;

-(Fraction *) div: (Fraction *) f;

@end

注意,这既是接口部分的定义,也是现有接口部分的扩展。因此,必须包括原接口部分,这样编译器就知道Fraction类。


按照惯例,作为分类的.h和.m文件的基本名称是由类的名称紧接着分类的名称。例如:FractionMathOps.m

一些程序员使用符号“+”来分隔类和分类的名称,比如Fraction+MathOps.h。呵呵,这个倒是有点像C语言的下划线分割一样。一般情况下就不要这么搞了。


类的扩展:

创建一个未命名的分类,且在括号“()”之间不指定名字,这是一种特殊的情况。这种特殊的语法定义为类的扩展。未命名类中声明的方法需要在主实现区域实现,而不是在分离的实现区域中实现。

未命名分类是非常有用的,因为它们的方法都是私有的。如果需要写一个类,而且数据和方法仅供这个类本身使用,未命名类比较合适。


关于分类的注意事项:

分类可以覆写该类中的另一个方法,但是通常认为这种做法是做虐的设计习惯。所以需要注意:

第一、覆写了一个方法后,再也不能访问原来的方法。(如果确实需要覆写方法,正确的选择可能是创建子类。)

第二、通过使用分类添加新的方法来扩展类不仅仅影响这个类,同时也会影响它的所有子类。

第三、对象/分类命名对必须是唯一的。因为大家使用的名称空间是程序代码、库、框架和插件共享的。


协议和代理:

协议是多个类共享的一个方法列表。协议中列出的方法没有相应的实现,计划由其他人来实现。

协议提供了一种方式,用指定的名称定义一组多少有点相关的方法。

如果决定实现特定协议的所有方法,也就意味着要遵守(confirm to)或采用(adopt)这项协议。

定义一个协议很简单:只要使用@protocol指令,然后跟上你给出的协议名称。例如:

@protocol NSCoping

- (id) copyWithZone: (NSZone *) zone;

@end


通过在@interface行的一对尖括号(<....>)内列出协议名称,可以告知编译器你正在采用的一个协议。这项协议的名称放在类名和它的父类名称之后,例如:

@interface AddressBook:NSObject <NSCoping>


如果你的类采用多项协议,只需把它们都列在尖括号中,并用逗号分开,例如:

@interface AddressBook:NSObject <NSCoping, NSCoding>


如果你定义了自己的协议,那么不必由自己实现它。如果一个类遵守NSCoping协议,则它的子类也遵守NSCoping协议(不过并不意味着对该子类而言,这些方法得到了正确的实现)。

@protocol Drawing

-(void) paint;

@required

-(void) erase;

@optional

-(void) outline;

@end

注意,这里使用了@optional指令。该指令之后列出的所有方法都是可选的。@required指令之后的是需要的方法。


注意,协议不引用任何类,它是无类的(classless)。任何类都可以遵循Drawing协议。

可以使用conformsToProtocol:方法检查一个对象是否遵循某些协议。例如:

if ([currentObject conformsToProtocol: @protocol (Drawing)] == YES) {

...

}


这里使用的专用@protocol指令用于获取一个协议名称,并产生一个Protocol对象。

通过在类型名称之后的尖括号中添加协议名称,可以借助编译器来检查变量的一致性。例如:

id <Drawing> currentObject;

id <NSCoping, NSCoding> myDocument;

定义一项协议时,可以扩展现有协议的定义。如:

@protocol Drawing3D <Drawing>


代理:

协议也是一种两个类之间的接口定义。定义了协议的类可以看做是将协议定义的方法代理给了实现它们的类。

非正式(informal)协议:是一个分类,列出了一组方法但并没有实现它们。因此,非正式分类通常是为根类定义的。有时,非正式协议也称为抽象(abstract)协议。

非正式协议实际上只是一个名称下的一组方法。

声明非正式协议的类自己并不实现这些方法,并且选择实现这些方法中的子类需要在它的接口部分重新声明这些方法,同时还要实现这些方法中的一个或多个。

注意:前面描述的@optional指令添加到了Objective-C 2.0语言中,用于取代非正式协议的使用。


合成对象(面向对象的那个合成吧):

可以定义一个类包含其他类的一个或多个对象。这个新类的对象就是所谓的合成(composite)对象,因为它是由其他对象组成的。

子类依赖于父类,改变了父类有可能会使得子类中的方法不能工作。


0 0
原创粉丝点击