类别是一种为现有的类添加新方法的方法。
声明类别
类别的声明格式和类的声明格式相似:
@interface NSString (NumberConvenice) //类别的名称是NumberConvenience,该类别将向NSString类中添加方法
<span style="font-family: Arial, Helvetica, sans-serif;">-(NSString *)lengthAsNumber;</span>
<span style="font-family: Arial, Helvetica, sans-serif;">@end </span>
声明具有两个特点:
- 现有的类位于@interface关键字之后,其后面是位于圆括号中的一个新名称。
- 制定向其添加类别的类(示例中是NSString)以及类别的名称,而且还可以列出添加的方法,以@end结束。
注意:不能添加新的实现变量,因此与类的声明不同的是,类别的声明中没有实例变量部分。
实现类别
与@interface部分对应的还有一个@implementation部分,可以在@implementation(意为:实现)部分实现自己的方法。
@implementation NSString (NumberConvenience )
-(NSNumber *)lengthAsNumber
{
unsigned int length = [self length ];
return ([NSNumber numberWithUnsignedInt:length ]);
} //lengthAsNumber
@end //NumberConvenience
与类别的@interface 部分类似,@implementation 部分也包含类名、类别名以及新方法的正文部分。
类别的局限性
类别有两大局限性:
- 无法向类中添加新的实例变量。类别没有位置容纳实例变量。
- 名称冲突,即类别中的放啊和现有的方法重名。档发生名称冲突的时候,类别具有更高的优先级。类别方法将完全取代初始化方法,从而无法在使用初始方法。
类别的作用
类别主要用于3个目的:
- 将类的实现分散到多个不同文件或多个不同框架中;
- 创建私有方法的前向引用;
如果编译器遇到当调用对象的某个方法,但没有找到该方法的生命或定义,则它将发出这样的错误提示:“warning:'CategoryThing' may not respond to '-settings:' ”通常情况下,这种错误提示将有助于捕获许多打字或排版错误。入股某些方法的实现使用了在类@interface部分未列出的方法,编译器将会提出警告。可以将类别放在实现文件的最前面,则编译器不会发出警告。
- 向对象添加非正式协议(informal protocol)
委托是一种对象,另一个类的对象会要求委托对象执行它的某些操作。例如,档AppKit类的NSApplication启动时,它会询问其委托对象是否应该打开一个无标题窗口。NSWindow类的对象询问他们自己的委托对象是否应该允许关闭某个窗口。
如ITunesFinder 委托的代码。
#import <Foundation/Foundation.>h
@interface ITunesFinder :NSObject
@end
</pre><pre name="code" class="objc">//基本声明
#import "ITunesFinder.h "
@implementation ITunesFinder
//委托方法
<pre name="code" class="objc">-(void)netServiceBrowser :(NSNetServiceBrowser *)b didFindService: (NSNetService *)service moreComing:(BOOL )moreComing { [service resolveWithTimeout :10]; NSLog(@"found one! Name is %@",[service name]); }//didFindService
委托和类别
委托强调类别的另一种应用:被发送给委托对象的方法可以声明为一个NSObject的类别。
响应选择器
选择器只有一个方法名称,但它以Object-C运行时使用的特殊方法编码,以迅速执行查询。使用@selector 预编译指令指定选择器,其中方法名位于圆括号中。如:
<span style="white-space:pre"> </span>@selector(setEngine :)
如果该委托对象能够响应给定的消息,被委托对象能向对象发送消息;否则,被委托对象将忽略该委托对象,继续正常运行。
选择器的其他应用
选择器可以被传递,可以作为方法的参数使用,甚至可以作为实例变量存储。