OC中的分类与类扩展

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

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

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

3、使用分类的方式。

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

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

如何定义分类\类扩展

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

@interface 要扩展的类名称(分类名称)。。。@end

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

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

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

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

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

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

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

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

#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的声明

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

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

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

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

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

类名+分类名.h/.m例如,对于Car的fly分类,我们应该命名文件

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

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

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

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

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

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

类扩展

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

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

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

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

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

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

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

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

2、分类扩展可以继承。

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

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

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

每一件事都要用多方面的角度来看它

OC中的分类与类扩展

相关文章:

你感兴趣的文章:

标签云: