objective-c 中的category 与Protocol 用法解释

来源:互联网 发布:迈卡威新秀数据 编辑:程序博客网 时间:2024/05/16 15:46
转载:http://blog.csdn.net/fanweiying/article/details/7354780

类别(Catagory) 

 

类别是扩展对象能力的一种方法。你可以在对象中添加新的method,但你不能添加新的实例变量。新的method被视为扩展的类的一部分,子类将继承这些新的method。如果你有两个覆盖一个类的method的类别,究竟哪一个覆盖并不确定。 

类别的语法与类的语法相似。他们都有interface和实现。当然,也有一些轻微的差别。类别定义的开头几行象这样: 

@interface ClassName (CatagoryName) 

@implementation ClassName (CatagoryName) 

ClassName是你要扩展的类的名称,CatagoryName是类别的识别的名称。类别可以访问所扩展的类的实例变量。 

其余的语法是相同的:在interface中声明method,在实现中定义它们,并以@end结束。 

你可以用类别建立私有method。把类别的interface放在类的实现文件的实现代码的前面。然后把你需要作为私有mthod的放在这个类别中。创建对象的实现,然后,在这个文件的末尾,加入类别的实现。这样可以对外隐藏这些method,如果在其他地方试图访问这些method,编译器将会给出警告。它不能够在运行时避免被访问,而只能在编译时警告你。在ObjC中没有办法禁止method被访问。 

 

协议(Protocol) 

 

协议,顾名思义,定义一组类之间相互遵守的行为规范。协议没有interface和实现,但他们与interface更加相似。你不需要添加新的实例变量,也不添加新的method或定义任何method的内部实现。协议所需要做的只是定义一套要求所有类都必须包含的method,以遵循这个协议。 

协议在你使用ObjC的动态类型机制的时候特别有用。ObjC拥有和Java类似的运行时的动态类型。这是它优于C++的一点,C++只支持“编译时”的动态类型。 

比如你要创建一个可以接受任何对象的method。你必须确定这个对象可以响应你要发送的消息,否则你将会发送这个对象不明白的消息给它。这会导致一些问题。如果你使用了协议,你就可以确保它能响应你将要发给它的许多消息,如果你仅是需要发送一个消息,你还有其它方法来检查……这一点我留给你自己去研究。 

同时,在上述的情况中,你还可以使协议要求你所期望的参数。我现在会展示给你看怎么完成这些工作。 

定义一个新的协议,首先: 

@protocol ProtocolName 

接着是任意数量的method的声明,请使用在interface定义的相同的语法。最后以@end结束。 

现在,为了遵循这个协议,你首先声明你要创建的新对象的interface的内容。然后,你必须在这个对象的实现中定义协议中的所有method。

@interface NewObject : Object 

上述的语句告诉编译器这是一个叫NewObject的对象,它的超类是Object,并要符合ProtocolName的协议。 

要查询一个对象是否满足特定的协议,可以使用“conformsTo"的mthod。 

[object conformsTo:@protocol(ProtocolName)]; 

这会根据对象是否符合的情况返回YES或NO。 

要查询一个参数是否符合特定的协议,可以象如下地声明method: 

-method:(id)argument; 

(译注:原文如此,在gcc中似乎并不支持,按照逻辑来说应该为:-method:(id ) argument;) 

你也可以返回满足协议的对象: 

-(id ) method; 

以下转自:zhiwei.li博客

Protocol

参考资料为  Programming in Objective-C 2.0 第2版(Pearson教育出版集团 2009)

简介:
Objective-C里的Protocol 与Java的Interface(接口) 或者 C++的purely virtual class(纯虚类)相同 ,就是用来 声明接口的

协议是 被许多类 共享的 方法的列表.  列在协议里的方法不负责实现;目的是让别人来实现(比如你).协议提供一种定义一组同特定的名称相关的方法的途径.  这些方法一般放在文档中,让你知道它们如何执行, 一般你能够在自己的类定义里 实现它.

如果协议中定义的方法有 @optional 指令, 如:
@protocol Drawing
-(void) paint;
-(void) erase;
@optional
-(void) outline;
@end

如何列在@otpional后面的方法都是 可选的, 也就是说不一定要实现它.上例中, 采纳Drawing这个协议的类,不是非要实现outline这个方法不可

如果是@required指令的后面的方法呢,那是一定要实现的

协议

协议声明那些由其他类实现的方法。协议至少在以下3个方面是有用的
1)声明那些期望由其他类实现的方法
2)为隐藏它的类的那些对象声明接口
3)为那些没有继承关系的类捕获它们之间的相同点

为其他类声明接口

Class和category接口 声明那些与特定的类相关的方法。
非正式协议和正式协议,声明的方法是与任何特定的类无关的

协议就是一个简单的方法声明的列表,不与类定义关联。举个例子,下面这些方法用来
报告用户的鼠标行为的,可以被收集到一个协议里:

- (void)mouseDown:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;

如果哪个类想要响应鼠标事件,那么就可采纳这个协议,实现这些方法。

因为协议与类的继承体系无关,所以可以用那些class和categories都不能使用的方式。
协议列出的那些方法被实现(或者可能被实现)在其他地方。不关心实现这些方法的类的实体,而关心是否有一个特殊的类 服从这个协议—-是否实现了协议定义的那些方法。
 

Catagory

 

想为现有的类添加新的行为时,通常会创建子类。如果没有源代码,便无法创建子类。但是可以通过创建Categories来实现。

比如,我想给NSString添加一个方法以判断它是不是一个URL,写法就像这样:
#import <Cocoa/Cocoa.h>
@interface NSString (Utilities)
- (BOOL) isURL;
@end
这很像一个类的声明。不同的地方在于后面没有列出父类,并且在括号里面写了类目的名称。类目的名字可以随便取,但是最好能表达出你在类目中包含的方法所要做的事。
类目(category)的局限性
第一,无法向类中添加新的实例变量。category没有位置容纳实例变量
第二,名称冲突,即 category中的方法与现有的方法重名。当发生名称冲突时,Categories具有更高的优先级。你的Categories方法将完全取代class的方法。有些编程人员会在自己的Categories方法中添加一个前缀,以确保不发生名称冲突。
这个实际上叫做 类目重写(override)
 
 
Categories的作用
1)将class的实现分散到多个文件或者框架中(splitting a class’s implementaion across multiple files or multiple frameworks)
2)创建对私有方法的前向引用 (creating forward references for private methods)
3) 往对象里添加非正式协议(adding informal protocols to an object. )
 
 
Cocoa没有任何真正的私有方法。只要知道对象支持的某个方法的名称,即使该对象所在的类的接口没有该方法,你也可以调用该方法
不过编译器会尽力提供帮助,如果编译器遇到你调用的对象的某个方法,但没有找到该方法的声明或者定义,则发出错误提示:
warning : ” may not respond to ”
但是,如果你的某些方法的实现使用了在类的@interface部分未列出的方法,编译器的这种警惕性将会带来一些问题。对于为什么不想在类的@interface部分类出自己的全部方法,有许多充分的理由。这些方法可能是纯粹的实现细节,你可能将根据方法名称来确定要使用哪个方法。但是不管怎样,如果你在使用自己的方法之前没有声明它们,编译器将发出警告。修复所有的编译器警告是一种良好的习惯,那么能做些什么呢?
 
 
只要在categories中声明一个方法,编译器就会表示:好了,该方法已经存在,如果遇到编程人员使用该方法,我不会提出警告。“ 实际上,你不必实现那些你不想实现的方法。
 
这个玩意,有点类似于 C++的纯虚函数,只声明,而不实现。
 
 
 
 
非正式协议和委托类目(Informal Protocols and Delegation Categories)
 
Cocoa的类经常使用一种名为delegate的技术,委托是一种对象,另一个类的对象会要求委托对象 执行它的某些操作。例如,当AppKit类的NSApplication启动时,它会询问其委托对象是否应该打开一个无标题窗口。 NSWindow类的对象询问它们自己的委托对象是否应该允许关闭某个窗口。
 
更常用的是,编写委托对象并将其提供给其他一些对象,通常是提供给Cocoa生成的对象。通过实现特定的方法,你可以控制Cocoa中的对象的行为。
 
Cocoa的滚动列表是由AppKit类的NSTableView处理的。当tableview对象准备好执行某些操作(例如选择用户刚刚点击的行)时,它询问 其委托对象是否选择此行。tableview对象给其委托对象发送一条消息:
-(BOOL) tableview: (NSTableView *) tableView shouldSelectRow :( int)  row;

原创粉丝点击