---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
在编写面向对象的程序的时候,我们经常想为现有的类添加一些新的行为。例如,你设计了一种新的类型轮胎,因此需要创建Tire类的子类并添加一些有趣的功能。为已经存在的类添加行为时,通常采用创建子类的方法。但是,有时创建子类并不方便。比如,你想要为NSString类添加一个新的方法。但是NSString实际上只是一个类簇的表面形式,因而这样的类创建子类非常困难。利用Objective-C的动态运行分配机制,尼克为现有的类添加新的方法。这些新方法在OC中被称为分类(category)。
创建分类
例如,你想要编写一个程序接收一系列的字符串,然后确定每个字符串的长度并存入NSArray或NSDictionary中。你需要先将每个长度的值包装在一个NSNumber对象中,然后才能存入NSArray或NSDictionary中。如:
NSNumber *number;
number = [NSNumber numberWithUnsignedInt: [string length]];
// … do something with number
我们可以使用分类来简化。通常把分类放在独立的文件中,以“类名称+分类名称”命名。这个程序可以写成如下:
@interface 部分
@interface NSString (NumberConvenience)
- (NSNumber *)lengthAsNumber;
@end
@implementation 部分
#import "NSString+NumberConvenience.h"
@implementation NSString (NumberConvenience)
- (NSNumber *)lengthAsNumber
{
NSUInteger length = [self length];
return ([NSNumber numberWithUnsignedInt:length]);
}
@end
然后是main函数:
#import <Foundation/Foundation.h>
#import "NSString+NumberConvenience.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:[@"hello" lengthAsNumber] forKey:@"hello"];
[dic setObject:[@"iLikeFish" lengthAsNumber] forKey:@"iLikeFish"];
[dic setObject:[@"Once upon a time" lengthAsNumber] forKey:@"Once upon a time"];
NSLog(@"%@", dic);
}
return 0;
}
程序运行后,得到如下结果:
分类的缺陷
分类有相隔局限性。
- 无法向类中添加新的实例变量。分类没有空间容纳实例变量
- 名称冲突,也就是分类中的方法与现有的方法重名。当发生名称冲突时,分类具有更高的优先级导致现有的方法不可以用。
分类的优势
- 将类的实现代码分散到多个不同文件或框架中
- 创建对私有方法的向前引用
- 向对象添加非正式协议
类扩展
有一个特殊的分类叫类扩展(class extension)。这个类的特点之一就是不需要名字。其特点如下:
- 它不需要名字
- 你可以在包含你的源代码的类中使用它
- 你可以添加变量
- 可以将只读权限改成读写权限
- 创建数量不限
下面是一个示例:
things.h如下:
#import <Foundation/Foundation.h>
@interface Things : NSObject
@property (assign) NSInteger thing1;
@property (readonly, assign) NSInteger thing2;
- (void)resetAllValues;
@end
这个类包含两个属性和一个方法。将thing2属性标记为只读。
thing.m如下:
#import "Things.h"
@interface Things ()
{
NSInteger thing4;
}
@property (readwrite, assign) NSInteger thing2;
@property (assign) NSInteger thing3;
@end
@implementation Things
@synthesize thing1;
@synthesize thing2;
@synthesize thing3;
- (void)resetAllValues
{
self.thing1 = 200;
self.thing2 = 300;
self.thing3 = 400;
thing4 = 5;
}
- (NSString *) description
{
NSString *desc = [NSString stringWithFormat: @"%d %d %d",
thing1, thing2, thing3];
return (desc);
} // description
@end
我们看其中的代码:
@interface Things ()
{
NSInteger thing4;
}
@property (readwrite, assign) NSInteger thing2;
@property (assign) NSInteger thing3;
@end
这里修改了thing2的属性,将只读变成了读写。我们改变了读写权限,将它标记为readwrite,这样编译器就会生成setter方法,不过它是只能在这个类中访问的私有方法,在公共接口只有getter方法。而且添加了thing3属性。此外,还添加了一个名为thing4的实例变量。
main.m文件如下:
#import <Foundation/Foundation.h>
#import "Things.h"
int main(int argc, const char * argv[])
{
@autoreleasepool
{
Things *things = [[Things alloc] init];
things.thing1 = 1;
NSLog(@"%@", things);
[things resetAllValues];
NSLog(@"%@", things);
}
return 0;
}
运行程序,会得到如下结果:
1 0 0
200 300 400
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------