在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;
@end

Car.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.h
Car+fly.m

3、在使用分类的扩展方法时,需要导入分类的.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中的分类与类扩展相关推荐

  1. OC 中的分类(Category)详解

    1.Category  分类.类别 2.分类:可以给某一个类扩充一些方法(不修改原来类的代码) 3.分类也分为声明(放在.h文件)和实现(放在.m文件): 分类的声明格式如下 @interface 类 ...

  2. Spring Boot2.0+中,自定义配置类扩展springMVC的功能

    在spring boot1.0+,我们可以使用WebMvcConfigurerAdapter来扩展springMVC的功能,其中自定义的拦截器并不会拦截静态资源(js.css等). @Configur ...

  3. iOS中分类(category)和类扩展(Extension)的区别

    iOS中分类(category)和类扩展(Extension)的区别 一.分类的定义: 分类是OC中的特有语法,它是表示一个指向分类结构体的指针,它是为了扩展系统类的方法而产生的一种方式. 二.分类的 ...

  4. Swift类扩展使用方法

    2019独角兽企业重金招聘Python工程师标准>>> Swift是没有OC中的分类的. 但可以进行类扩展, 一般用于实现代理方法. 类扩展中无法定义属性 使用方法: extensi ...

  5. [OC学习笔记]分类和关联对象源码解析

    我们平时在开发的时候经常会使用分类来添加方法.协议.属性,但在添加属性的时候属性是不会自动生成成员变量的,这时候我们就需要关联对象来动态存储属性值. 分类 @interface NSObject(St ...

  6. OC中类别、扩展、协议与托付

    类别(category)--通过使用类别,我们能够动态地为现有的类加入新方法.并且能够将类定义模块化地分不到多个相关文件里.通常仅仅在类别中定义方法. 类别,接口部分的定义,通常该文件命名为已有&qu ...

  7. 中小型超市系统中的分类/产品属性/扩展属性的数据库设计

    中小型商城系统中的分类/产品属性/扩展属性的数据库设计 正文: 之前发表过一篇"商城系统中[商品扩展属性]的表单生成及客户端验证",部分童鞋对于后台数据库的设计比较感兴趣,于是今天 ...

  8. OC中category(分类)中添加属性

    OC中category(分类)中添加属性 因为OC中无法添加成员变量并且添加的属性不会被保存,所以需要重写get和set方法来实现属性的保存. //setter //self表示属性拥有者是当前类, ...

  9. 中小型商城系统中的分类/产品属性/扩展属性的数据库设计

    声明:之所以定位在"中小型"商城系统,而非"大型"(指淘宝.拍拍这类巨无霸),理由很简单----我一直都呆在(创业型的)小公司,没见过这些大家伙是怎么设计的:) ...

  10. 【Groovy】Groovy 扩展方法 ( 实例扩展方法配置 | 扩展方法示例 | 编译实例扩展类 | 打包实例扩展类字节码到 jar 包中 | 测试使用 Thread 实例扩展方法 )

    文章目录 一.扩展方法示例 二.实例扩展方法配置 三.编译实例扩展类 四.打包静态扩展类字节码到 jar 包中 五.测试使用 Thread 实例扩展方法 一.扩展方法示例 为 Thread 扩展 he ...

最新文章

  1. MySQL实战课程---通过录像手把手带您学会当前互联网流行架构
  2. acf滞后数必须为正整数。_【知识点】“勾股定理”的必考点,必须掌握!
  3. 学web前端开发有前途吗
  4. linux root ssh 安全,linux ssh安全加固方法
  5. Hbase PageFilter 取出数量不准确问题
  6. linux5 多用户模式,centos7设置以多用户模式启动
  7. 计算机中丢失ENWeb,webapi session 丢失
  8. Kubernetes入门——Longhorn简介
  9. 硬件设备监控之Sigar的配置与使用
  10. 目前在读学生的Java学习之路
  11. VS2015 解决 “有太多的错误导致IntelliSense引擎无法正常工作,其中有些错误无法在编辑其中查看”问题
  12. Datagrip连接mysql错误[08S01]解决办法
  13. 斑马电商云品牌发布会就是一群有梦想的人在搞事情
  14. C++中string子串
  15. 【Linux】工具使用
  16. this指向,并改变this指向
  17. WLAN AP安全策略中WPA认证与WPA2认证的差异
  18. QlikView 笔记(一) 初次使用时最让我惊喜的函数
  19. 计算机动画专业要学什么课程,贵阳市计算机学校3D动画设计专业需要学哪些课程?...
  20. 【厚积薄发系列】C++项目总结18—调用第三方库接口编译无错误但得不到预期结果

热门文章

  1. ActiveMQ 简介
  2. 周易内核与计算机原理,周易原理之我说(一)
  3. 前端必备:从头开始,搞懂Promise之Promise基础
  4. Linux错误码汇总
  5. python中idle什么意思_始学Python:IDLE环境介绍
  6. 鸿蒙太空是什么意思,我所居兮,青埂之峰:我所游兮,鸿蒙太空,谁与我逝兮,吾谁与从?渺渺茫茫兮归彼大荒!什么意思?求解...
  7. 利用吉洪若夫正则化及其西尔韦斯特方程来修复受损图像
  8. l2tp 账户管理系统
  9. django账户管理系统admin
  10. 神经网络能用来干什么_秒懂神经网络---震惊!!!神经网络原来可以这么简单!...