zoukankan      html  css  js  c++  java
  • 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)添加方法。这样的优点在于,你不需要去创建一个子类更新存在的代码,但是必须要小心不要去重写已经存在的方法。对于小的工程,分类完全没有必要使用,可以用协议或者子类化去实现这种功能。
         
         
  • 相关阅读:
    模板 无源汇上下界可行流 loj115
    ICPC2018JiaozuoE Resistors in Parallel 高精度 数论
    hdu 2255 奔小康赚大钱 最佳匹配 KM算法
    ICPC2018Beijing 现场赛D Frog and Portal 构造
    codeforce 1175E Minimal Segment Cover ST表 倍增思想
    ICPC2018Jiaozuo 现场赛H Can You Solve the Harder Problem? 后缀数组 树上差分 ST表 口胡题解
    luogu P1966 火柴排队 树状数组 逆序对 离散化
    luogu P1970 花匠 贪心
    luogu P1967 货车运输 最大生成树 倍增LCA
    luogu P1315 观光公交 贪心
  • 原文地址:https://www.cnblogs.com/zhanggui/p/4666489.html
Copyright © 2011-2022 走看看