OC中的分类与类扩展

    xiaoxiao2025-03-13  15

    在OC中,对于已有的类进行扩展,我们有两种方式:

    1、在原始类的定义中,进行代码扩展。

    2、通过继承的方式,扩展子类。

    3、使用分类的方式。

    第一、二种方式不用多说,第三种方式则是OC中比较有特色的功能。

    分类允许我们在不更改类的原始代码的情况下,实现对类的功能扩展,包括:添加实例方法,类方法与实例变量,属性(添加实例变量与属性需要匿名分类——类扩展)。

    如何定义分类\类扩展

    定义分类,很简单,只需要指出你需要扩展的类,分类名称和你要定义的分类的方法即可。其余均类似定义普通的类。形式如下

    [objc]  view plain  copy @interface  要扩展的类名称(分类名称)   。。。   @end  

    分类根据有无分类名称,可以分为 分类 和 类扩展(匿名分类)。

    而分类又可根据其实现方式,分为两种:

    1、分别新建分类.h与分类.m文件,在独立于原始类的文件中编写分类代码。

    2、在原始类文件的.h或.m中声明分类,在原始类的.m文件中实现分类。

    新建.h与.m,编写类的分类

    例如,我们写了一个Car类,定义如下:

    [objc]  view plain  copy #import <Foundation/Foundation.h>         @interface Car : NSObject   @property(nonatomicstrong)NSString* name;   @property(nonatomicgetter=leftGas) NSUInteger totalGas;      -(instancetype)initWithName:(NSString*) name;      -(void) run;   -(void) addGas:(NSUInteger) gas;   @end   这一个基本的Car类,让我们的汽车可以行驶(执行run方法)。但是,某天我突发奇想,想让我的汽车能够飞起来,于是我想在Car中添加fly方法,但又不想改写原始的类文件,OK,这时候就用到了类的分类,分类名称fly,定义如下:

    [objc]  view plain  copy #import "Car.h"  // 注意,我们这里导入了Car.h文件,让分类知道Car类的存在      @interface Car (Fly)   -(void) fly;   @end   在分类的实现文件中,有如下代码来实现飞行:

    [objc]  view plain  copy #import "Car+Fly.h"      @implementation Car (Fly)      -(void) fly   {       NSLog(@"%@ is flying"self.name);  // 这里通过self存取方法,获得Car类的name属性值   }   @end   上面的代码值得注意的一点是,fly函数通过self方式取得了name属性,这里其实表明分类对于类属性的访问,其实是和类本身定义一样的。(但不能够通过_name属性名称直接访问属性,否则会提示未定义)。这一点同继承不同(属性对于子类是不可见的,子类只能通过继承得到的存取方法访问属性)。

    关于新建.h与.m编写新的分类,有这么几点注意:

    1、分类能够像类本身一样,调用self来访问类的方法,属性。

    其实将分类理解成类本身更好,因为除了声明方式不一样外,分类对原始类方法,属性,及实例方法的访问,均与类本身访问方式无二。但对于过新建.h与.m来写的分类来说,分类对于原始类的了解(即知道其中存在哪些方法,属性),仅通过原始类的接口文件(.h文件),这与在类外部方法类定义的一些内容是一样的,仅仅能够看到.h中的定义

    比如,我们在原始类的.m文件中,定义了一个fire方法,而在.h文件中并没有声明该方法(fire此处为私有方法)

    Car.h,没有对fire的声明

    [objc]  view plain  copy @interface Car : NSObject   @property(nonatomicstrong)NSString* name;   @property(nonatomicgetter=leftGas) NSUInteger totalGas;      -(instancetype)initWithName:(NSString*) name;      -(void) run;   -(void) addGas:(NSUInteger) gas;   @end   Car.m 直接实现没有声明过的fire方法,该方法在类外部不可见,但类中可以通过[self fire]形式调用 

    [objc]  view plain  copy @implementation Car   ....   -(void) fire   {       NSLog(@"%@ fire!"self.name);   }   ....   @end   那么对于fire方法,在分类fly中是无法调用到的,若调用该方法,则会提示未定义的错误

    同样的,分类对于原始类的属性的调用,仅能够通过存取方法,若直接用属性名称的话(属性名称仅在原始类的.m中可见),则会提示未定义错误

    2、对于新建.h,.m分类文件,我们的命名应当遵循XCode的默认命名规则。

    在Xcode中创建类的分类文件时,会默认以下面方式命名:

    [objc]  view plain  copy 类名+分类名.h/.m   例如,对于Car的fly分类,我们应该命名文件

    [objc]  view plain  copy Car+fly.h   Car+fly.m   3、在使用分类的扩展方法时,需要导入分类的.h文件,才能让执行代码知道分类扩展方法的存在。实际上,由于在分类文件中我们已经导入了原始类的头文件,所以在使用分类时,仅仅导入分类头文件即可。

    4、分类能够对实例方法,类方法进行扩展,但不能够添加类的属性及实例变量。

    在原始类文件的.h或.m中声明分类,在原始类的.m文件中实现分类

    通过改写原始类的方式实现分类,个人感觉用处不大(这和直接改写原始类有什么区别呢?)。

    在原始类中编写分类,与新建文件编写分类的区别有:

    1、对于原始类的可视程度,在原始类中编写的分类是和类本身一样的(即可访问私有方法及通过属性名访问属性),这与新建文件编写的分类是不同的。

    类扩展

    类扩展其实是一种特殊的分类,即匿名分类,如下格式

    [objc]  view plain  copy @interface Car ()   -(void) fire;   @property(nonatomic) NSUInteger price;   @end   括号中并未给出分类名称,这种分类有个专业名称—— 类扩展

    类扩展与分类的区别如下:

    1、类扩展仅能够在原始类中声明(.h或.m中均可,在.m中声明的类扩展其定义的属性和方法均是私有的)

    2、类扩展的实现仅能够在原始类的.m中编写。

    3、在类扩展中可以扩展类的属性,而在分类中仅能够扩展实例方法和类方法。

    对于类分类,有几点比较有意思:

    1、对于Cocoa中的类,我们也可以进行分类扩展,特别是对于NSObjec类,我们对其扩展,那么所有的类均可以调用我们的扩展方法!

    2、分类扩展可以继承。

    3、对于分类或扩展中声明的方法,我们并不要必须实现,而是在必要时,才会有某个类来实现,这点和协议很像。

    4、对于类中的同名方法,分类扩展会覆盖其实现。

    5、对于类的私有方法,我们可以在分类扩展中将其声明为可见的(而不实现),这样在类外部就可以调用该类的私有函数了。

    FROM:  http://blog.csdn.net/u013378438/article/details/44491703

    转载请注明原文地址: https://ju.6miu.com/read-1297001.html
    最新回复(0)