在平常的开发中,可能会碰到这样的需求:给某个类增长方法。好比说,须要给NSString类增长一个打印的方法。固然,咱们能够新建一个类好比TestString,并继承NSString类,在新的类TestString中实现 displayString方法。可是,这种方法有一个明显的缺陷是:只有 TestString类有该方法,NSString类的其余子类,好比 NSMutableString 不能使用该方法。可否给 NSString 类增长一个方法,让NSString以及NSString的全部子类均可以使用呢?答案能够的,Category能够完美的解决这个问题。编程
Objective-C 中使用Category的语法是使用 @interface关键字,和定义一个标准的类很是相似,不过不是使用冒号(:,:是继承一个类时使用),而是使用 (),以下:app
@interface NSString (PlayString) - (void)playString:(NSString *)content; @end
其中:括号内的 PlayStirng 是Category的名称。函数
能够为任何一个类增长 Category,即便看不到这个类的源代码。当为一个类增长Cateogry后,这个类以及这个类的全部子类均可以使用Category中的方法。在运行时,Category 中的方法和类中原来的代码是没有区别的。好比说,上例中,NSString 类增长Cateogry,Category中定义了 playString方法,该方法的实现以下:this
- (void)playString:(NSString *)content { NSLog(@"the content is %@",content); }
这样,NSString类的实例对象,以及NSString类的全部子类的实例对象,均可以使用 playString方法。以下:spa
NSString *myString = @"this is original NSString"; [myString playString:myString]; NSMutableString *mutString = [[NSMutableString alloc] init]; [mutString appendString:@"this is a subclass of NSString"]; [mutString playString:mutString];
除了给一个类增长方法外,Category 还有如下两种使用场景:code
1:将一个大的、复杂的类文件拆分红几个小的类文件。对象
2:多我的开发同一个类文件时,可使用Category,分别开发本身的功能。blog
1:Category中方法的命名。继承
(1):尽可能不要和原始类中的方法重名,尽管这样是合法的,可是和原始类中的方法重名绝对不是一个好的编程习惯。由于这样形成的后果是,不管是原始类,仍是原始类的子类,都没法使用原始类中的那个方法。一般来讲,想要覆盖父类中某个方法的状况,更适合用继承来实现,而不是Category。内存
(2):当一个原始类有多个 Category 时,各个Category 中的方法名要保持相异。尽管多个Category中方法名重复不会提醒错误,可是会发生一些莫名其妙的错误。多个Category中的方法名重复时,每一个Category都会向原始类中增长一个函数,这样在运行时,所调用的方法和咱们所指望的可能会不一致。这种状况下,具体调用哪一个Category中的方法和编译器是相关的。
2:Category中不能增长实例变量。虽然在Category中能够增长属性,可是在 .m文件中,编译器不会自动合成实例变量,以及访问实例变量的 getter/setter 方法。想要为某个原始类增长实例变量,这种状况能够用继承来实现。
实际上,Objective-C 中的类通过编译后,在内存中都有一个方法列表,方法列表指向的是该方法的代码块地址。当向某个方法发送消息时,就从方法列表中寻找方法。举例来讲有一个类 Person,该类通过编译后生成的方法列表是: setName、getName、getSex ……。如今该类增长一个Category,Category中也实现了方法getName,则再次通过编译后,生成的方法列表是: setName、getName(Category)、getName(原始类)、getSex ……,当给getName方法发送消息时,从类的方法列表中寻找,找到第一个getName方法时,就不在继续往下寻找,这样使用的永远是 Category中实现的 getName 方法。这也是为什么要注意Category中方法命名的缘由。