天天看點

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;
}