Fork me on GitHub

Objective-C使用Category

Category是ObjC语言中的扩展机制之一,另一个为Protocol。

Category提供一种为某个类添加方法而又不必编写子类的途径。

假设有这样一个类CarInfo:

#import <Foundation/Foundation.h>

@interface CarInfo : NSObject {

}

-(void)sayCarBrand;

@end

@implementation CarInfo

-(void) sayCarBrand{
NSLog(@"Car brand: Golf");
}

@end


我可以用Category为该类增加新的方法:

 #import <Foundation/Foundation.h>
#import "CarInfo.h"

@interface CarInfo(CarInfoCategory)

-(void)sayCarBrandChinese;

@end



@implementation CarInfo(CarInfoCategory)

-(void)sayCarBrandChinese{
NSLog(@"汽车品牌:高尔夫");
}

@end


这里的Category增加了一个新的方法,用来显示汉字名称。可在其他代码中直接调用,就如同调用CarInfo其他实例方法一样:

 

CarInfo *carInfo=[[CarInfo alloc] init];
[carInfo sayCarBrandChinese];



这种效果是Java做不到的。这得益于ObjC语言方法调度程序这一特殊机制。

如果方法名称相同会怎样?比如:

#import <Foundation/Foundation.h>
#import "CarInfo.h"

@interface CarInfo(CarInfoCategory)

-(void)sayCarBrand;

@end

@implementation CarInfo(CarInfoCategory)

-(void)sayCarBrand{
NSLog(@"汽车品牌:高尔夫");
}

@end



再次调用:

 
CarInfo *carInfo=[[CarInfo alloc] init];
[carInfo sayCarBrand];

会发现,打印的是category中的方法,而不是类的实例方法。因为category优先于类实例方法。

那么是否有这样的能力,比如在category的方法内代码中调用类的实例方法,这样不就可以实现类似Java方法拦截器的功能了么?或者说是方法代理模式。遗憾的是,这样不可以。
原文链接:http://marshal.easymorse.com/archives/4183

 

 

Objective C 2.0 简明教程 Category

 

Category为我们提供了区别于继承的另外一种方法来对类进行扩展。我们可以向任何已有的类添加成员函数来实现功能上的扩展(注:category只允许添加成员函数,不能添加数据成员),添加的函数可以访问类中所有的数据成员,该类的子类也将继承新添加的成员函数。

假设我们需要扩展前面几节用到的book类,添加一个名为Abstract的成员函数来输出书籍的摘要。使用category的格式为:

在头文件中声明category:

@interface 需要扩展的类(category名称)
//需要添加的函数
@end

可以看到,声明category的方法同类的声明非常类似。回到我们的例子,如果我们需要向Book类添加Abstract成员函数,对应的声明文件如下所示

// Book+Abstract.h
 
#import <Cocoa/Cocoa.h>
#import "Book.h"
 
 
@interface Book(Abstract)
-(NSString*) Abstract;
@end

注意推荐的文件命名规则:类名+category名.h

接下来我们需要对添加的abstract函数进行定义,如下所示:

// Book+Abstract.m
 
#import "Book+Abstract.h"
 
 
@implementation Book(Abstract)
-(NSString*)Abstract{
NSString* retstr = [[NSString alloc]initWithString:@"The story is..."];
[retstr autorelease];
return retstr;
}
@end

implementation文件的命名规则与头文件相似:类名+category名.m

作为演示,我们只是在Abstract函数中简单的输出一个NSString。下面我们来看客户端如何调用:

#import <Foundation/Foundation.h>
#import "Book.h"
#import "Book+Abstract.h"
 
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
NSString* name = [[NSString alloc] initWithString:@"Harry Porter"];
NSNumber* number = [[NSNumber alloc] initWithInt:100];
Book *book = [[Book alloc] initWithTitle:name andNumofpages:number];
[number release];
[name release];
 
NSLog(@"Abstract: %@", [book Abstract]);
[book release];
 
[pool drain];
return 0;
}

 

 

为什么对类进行扩展的feature被称作category?该名称应该反映了某种初衷,那就是当某个类比较复杂庞大时,我们可以对它的功能(也就是成员函数)进行分类,并且把它们放入不同的文件加以实现。

 

 类别:category
  类别:为现有的类添加新方法的方式。
  创建(.h文件):
  @interface NSString (NumberConvenience)
  - (NSNumber *) lengthAsNumber; //需要添加的方法
  @end //NumberConvenience
  实现(.m文件):
  @implementation NSString (NumberConvenience)
  - (NSNumber *) lengthAsNumber
  {
  //函数体
  }
  @end //NumberConvenience
  局限性:
  1 无法添加实例变量;
  2 名称冲突。
  作用:
  1 利用类别进行分散实现;把一个类实现为多个不同的类别,在类别(逻辑分组)中将方法组织起来。
  2 使用类别创建向前引用;
  3 非正式协议&委托&类别:被发送给委托对象的方法可以声明为一个NSObject的类别。某个类让委托对象执行该类自己的某些操作。
  非正式协议:创建一个NSObect的类别称为”创建一个非正式协议“;
  委托:一种对象,另一个类的对象会要求委托对象执行它的某些操作。
  如何知道委托对象能否处理发送给他的响应消息?
  首先检查对象,询问能否响应该选择器,如果该对象能够响应该选择器,则给它发送消息。

posted on 2012-02-12 07:11  pengyingh  阅读(191)  评论(0)    收藏  举报

导航