轉載:http://book.51cto.com/art/201105/262265.htm
category是Objective-C里面最常用到的功能之一。category可以為已經存在的類增加方法,而不需要增加一個子類。另外,category使得我們在不知道某個類的內部實現的情況下,為該類增加方法。
如果我們想增加某個框架(framework)中的類的方法,category就非常有效。比如,如果想在NSString上增加一個方法來判斷它是否是一個URL,那就可以這么做:
#import ……
@interface NSString (Utilities)
- (BOOL) isURL;
@end
這跟類的定義非常類似,區別就是category沒有父類,而且在括號里面要有category的名字。名字可以隨便取,但是名字應該讓人比較明白category里面有些什么功能的方法。下面的例子添加了一個判斷URL的方法。
#import "NSStringUtilities.h"
@implementation NSString (Utilities)
- (BOOL) isURL
{
if ( [self hasPrefix:@"http://"] )
return YES;
else
return NO;
}
@end
現在可以在任何的NSString類對象上調用這個方法了。下面的代碼在控制臺上打印“string1 is a URL”。
NSString*string1= @"http://www.xinlaoshi.com/";
NSString*string2= @"Pixar";
if ( [string1 isURL] )
NSLog (@"string1 is a URL");
if ( [string2 isURL] )
NSLog (@"string2 is a URL");
從上面的例子看出,通過類別所添加的新方法就成為類的一部分。我們通過類別為NSString添加的方法也存在于它的方法列表中,而為NSString子類添加的新方法,NSString類是不具有的。通過類別所添加的新方法可以像這個類的其他方法一樣完成任何操作。在運行時,新添加的方法和已經存在的方法在使用上沒有任何區別。通過類別為類所添加的方法和別的方法一樣會被它的子類所繼承。
類別接口的定義看起來很像類接口定義,而不同的是類別名使用圓括號列出,它們位于類名后面。類別必須導入它所擴展的類的接口文件。標準的語法格式如下:
#import "類名.h"
@interface類名(類別名)
//新方法的聲明
@end
和類一樣,類別的實現也要導入它的接口文件。一個常用的命名約定是,類別的基本文件名是這個類別擴展的類的名字后面跟類別名。因此,一個名字為“類名”+“類別名”+“.m”的實現文件看起來就像這樣:
#import "類名類別名.h"
@implementation類名(類別名)
//新方法的實現
@end
注意,類別并不能為類聲明新的實例變量,它只包含方法。然而,在類作用域中的所有實例變量,都能被這些類別方法所訪問。它們包括為類聲明的所有實例變量,甚至那些被@private修飾的變量。可以為一個類添加多個類別,但每個類別名必須不同,而且每個類別都必須聲明并實現一套不同的方法。
要記住的是,當我們通過category來修改一個類的時候,它對應用程序里的這個類的所有對象都起作用。跟子類不一樣,category不能增加成員變量。我們還可以用category來重寫類原先的存在的方法(我們并不推薦讀者這么做)。最后下面給出本節的完整例子。
【例5-4】categories實例。
NSStringUtilities.h的代碼如下:
#import/Cocoa.h>
@interface NSString (Utilities)
-(BOOL)isURL;
@end
NSStringUtilities.m的代碼如下:
#import "NSStringUtilities.h"
@implementation NSString (Utilities)
-(BOOL)isURL{
if ([self hasPrefix:@"http://"]) {
return YES;
}else {
return NO;
}
}
@end
測試類UseCategories.m的代碼如下:
#import/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init];
NSString *string1= @"http://www.xinlaoshi.com/";
NSString *string2= @"Pixar";
if ([string1 isURL]) {
NSLog(@"string1 is a URL");
}else {
NSLog(@"string1 is not a URL");
}
if ([string2 isURL]) {
NSLog(@"string2 is a URL");
} else {
NSLog(@"string2 is not a URL");
}
[pool drain];
return 0;
}
【程序結果】
string1 is a URL
string2 is not a URL