OC中的分类与类扩展

2024-09-06 00:48
文章标签 分类 扩展 oc

本文主要是介绍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;
@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中的分类与类扩展的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140523

相关文章

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

用Pytho解决分类问题_DBSCAN聚类算法模板

一:DBSCAN聚类算法的介绍 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法,DBSCAN算法的核心思想是将具有足够高密度的区域划分为簇,并能够在具有噪声的空间数据库中发现任意形状的簇。 DBSCAN算法的主要特点包括: 1. 基于密度的聚类:DBSCAN算法通过识别被低密

PHP7扩展开发之数组处理

前言 这次,我们将演示如何在PHP扩展中如何对数组进行处理。要实现的PHP代码如下: <?phpfunction array_concat ($arr, $prefix) {foreach($arr as $key => $val) {if (isset($prefix[$key]) && is_string($val) && is_string($prefix[$key])) {$arr[

PHP7扩展开发之字符串处理

前言 这次,我们来看看字符串在PHP扩展里面如何处理。 示例代码如下: <?phpfunction str_concat($prefix, $string) {$len = strlen($prefix);$substr = substr($string, 0, $len);if ($substr != $prefix) {return $prefix." ".$string;} else

PHP7扩展开发之类型处理

前言 这次,我们将演示如何在PHP扩展中如何对类型进行一些操作。如,判断变量类型。要实现的PHP代码如下: <?phpfunction get_size ($value) {if (is_string($value)) {return "string size is ". strlen($value);} else if (is_array($value)) {return "array si

PHP7扩展开发之依赖其他扩展

前言 有的时候,我们的扩展要依赖其他扩展。比如,我们PHP的mysqli扩展就依赖mysqlnd扩展。这中情况下,我们怎么使用其他扩展呢?这个就是本文讲述的内容。 我们新建立一个扩展,名字叫 demo_dep , 依赖之前的say扩展。 在demo_dep扩展中,我们实现demo_say方法。这个方法调用say扩展的say方法。 代码 基础代码 确保say扩展的头文件正确安装到了php