Categories  VS Extensions (分类 vs 扩展)

一、Categories(分类)
     Categories是一个把单个类定义分作好几个文件的方式。它的目标是通过模块化减少代码量比较大的压力。这避免了你的代码成为1000+行的文件,这样操作和分配精确几乎是不可能的。一个好的类定义是一个独特开发者必须的。
          
     这个图是用多个文件来实现Car类。
 
           在这个模块,我们在不接触它的类原始文件的情况下,使用分类来扩展已经存在的类。我们将学到如何使用这个功能来仿生保护方法(Protected methods)。Extensions和category关联很大,一会再说。
     设置
           再我们开始试验categories时,我们需要一个类去操作,创建/改变你的已经存在的类,代码如下:
       Car.h
#import <Foundation/Foundation.h>
 
@interface Car : NSObject
 
@property(copy,nonatomic)NSString *model;
@property(readonly) double odometer;
 
-(void)startEngine;
-(void)drive;
-(void)turnLeft;
-(void)turnRight;
@end
它的实现知识一些描述消息,因此我么可以再不同方法调用时发现。
#import "Car.h"
@implementation Car

-(void)startEngine
{
    NSLog(@"starting the %@'s engine" ,_model);
}
-(void)drive
{
    NSLog(@"The %@ is now driving",_model);
}
-(void)turnLeft
{
    NSLog(@"The %@ is turning left",_model);
}
-(void)turnRight
{
    NSLog(@"The %@ is turn right",_model);
}
@end
现在,让我们添其他方法到Car中,我们不去操作Car.h或者Car.m文件,我们可以用一个专用的分类去放置自己的函数方法。
创建Categories
     File—>New File—>iOS中选择Source—>Objective-C File,然后就会看到下图的选项,File Type 包括Empty File,Category,Protocol和Extension。
          File是文件名,Class是你想要扩展的类。
          当我们创建完成后,会生成两个文件,一个Car+Maintenance.h和一个Car+Maintenance.m
           Car+Maintenance.m
#import "Car+Maintenance.h"
 
@implementation Car (Maintenance)
 
@end  
       分类名字的约束是一个类的不同分类名字不能相同。正宗的文件命名协定是用类名+分类名。
        在Car+Maintenance.h
#import "Car.h"
 
@interface Car (Maintenance)
 
@end
     我们可以看到,它几乎和其他的类一样,只不过多了一个小括号,里面是分类名称,让我们添加一些新的方法到这里:
#import "Car.h"
 
@interface Car (Maintenance)
 
-(BOOL)needsOilChange;
-(void)changeOil;
-(void)rotateTires;
-(void)jumpBatteryUsingCar:(Car *)anotherCar;
@end
     在运行的时候,他们就会成为类的一部分,尽管他们没有在一个文件中声明,你可以像访问原始文件中的方法一样去访问分类中的方法。
     当然了,你必须去实现这些方法。它的实现和原始文件实现几乎一样,除了类名称后面多了一个括号。
#import "Car+Maintenance.h"
 
@implementation Car (Maintenance)
 
-(BOOL)needsOilChange {
    return YES;
}
-(void)changeOil {
    NSLog(@"Changin oil for the %@",[self model]);
}
-(void)rotateTires {
    NSLog(@"Rotation tires for the %@",[self model]);
}
-(void)jumpBatteryUsingCar:(Car *)anotherCar {
    NSLog(@"Jumped the %@ with a %@",[self model],[anotherCar model]);
}
@end
    还有重要的一点,分类也可以用于重写在原始类文件中已经存在的方法,(例如startEngine method),但是千万不要这样做。原因是分类是扁平式组织结构,如果你重写已经存在的方法,OC就不知道该调用哪个方法,在这种情况下,子类化是一个更好的选择。
  使用Categories
    要想使用分类只需要把.h文件导入即可,这样分类中的方法即可使用。
  #import "Car+Maintenance.h"
如果你删除了分类,那么你就会找不到定义的方法。
  保护方法(Protected)
     但是,分类并不是简单的把类定义放到几个文件中,他是一个强大的组织工具。我们可以定义类似保护访问的修改器,方法是在一个专用的分类中,定义一个protected 接口,然后之把它导入父类实现文件中,这样就定义了保护方法,而且使它们保持隐蔽。例如我们创建Car+Protected.h,然后直接导入父类的实现文件中。
     
#import "Car.h"
#import "Car+Protected.h"
 
@implementation Car
...
- (void)drive {
    [self prepareToDrive];
    NSLog(@"The %@ is now driving", _model);
}
...
 

     就像上边这样。

二、Extensions(扩展)
     它和分类很像,都是在原始类文件之外,允许你添加新的方法。但是与分类形成对照。extension’API必须再主实现中实现,它不能在分类中实现。
     记住一点,私有方法可以用把分类引入到实现文件中(而不是接口文件)实现私有效果,这些再你有很少的私有方法时可以实现,但是对于一个比较大的类就显得比较笨拙,扩展就是解决这个问题,它允许你声明正式的私有API.
     例如,如果你想把engineIsWorking方法正式的加入到Car中,你可以在Car.m包括一个扩展.它仍是一个私有方法,扩展的语法就像一个空的分类。
#import "Car.h"
@interface Car ()
-(BOOL)engineIsWorking;
@end
     它只有一个.h文件。然后在Car.m中去实现:
 
#import "Car.h"
#import "Car_Car.h"
@implementation Car
 
-(void)startEngine
{
    NSLog(@"starting the %@'s engine" ,_model);
}
-(void)drive
{
    NSLog(@"The %@ is now driving",_model);
}
-(void)turnLeft
{
    NSLog(@"The %@ is turning left",_model);
}
-(void)turnRight
{
    NSLog(@"The %@ is turn right",_model);
}
-(BOOL)engineIsWorking {
     return YES;
}
 @end
     另外,为了声明一个正式的私有API,扩展还可以重定义属性。这通常是用来使属性就像读写属性一样,同时保持只读到其他对象中。
     例如:
 
#import "Car.h"
 
@interface Car ()
@property(readwrite) double odometer;
-(BOOL)engineIsWorking;
@end
     我们可以在内部实现中指定self.odometer的值,但是再Car.m外就会编译失败。
三、总结
     分类是把类模块化道不同文件中的一种方式。扩展提供相似的功能,除了他的API必须要在主实现中公开。
      在组织大量代码库时,最常见的分类使用就是给内置数据类型(NSString 、NSArray)添加方法。这样的优点在于,你不需要去创建一个子类更新存在的代码,但是必须要小心不要去重写已经存在的方法。对于小的工程,分类完全没有必要使用,可以用协议或者子类化去实现这种功能。
     
     
posted @ 2015-07-22 09:59  zhanggui  阅读(584)  评论(0编辑  收藏  举报