OC中的分类与类扩展

2023-11-18

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

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

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

3、使用分类的方式。

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

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


如何定义分类\类扩展

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

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

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

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

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

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


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

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

[objc]  view plain  copy
  1. #import <Foundation/Foundation.h>  
  2.   
  3.   
  4. @interface Car : NSObject  
  5. @property(nonatomicstrong)NSString* name;  
  6. @property(nonatomicgetter=leftGas) NSUInteger totalGas;  
  7.   
  8. -(instancetype)initWithName:(NSString*) name;  
  9.   
  10. -(void) run;  
  11. -(void) addGas:(NSUInteger) gas;  
  12. @end  

这一个基本的Car类,让我们的汽车可以行驶(执行run方法)。但是,某天我突发奇想,想让我的汽车能够飞起来,于是我想在Car中添加fly方法,但又不想改写原始的类文件,OK,这时候就用到了类的分类,分类名称fly,定义如下:

[objc]  view plain  copy
  1. #import "Car.h"  // 注意,我们这里导入了Car.h文件,让分类知道Car类的存在  
  2.   
  3. @interface Car (Fly)  
  4. -(void) fly;  
  5. @end  

在分类的实现文件中,有如下代码来实现飞行:

[objc]  view plain  copy
  1. #import "Car+Fly.h"  
  2.   
  3. @implementation Car (Fly)  
  4.   
  5. -(void) fly  
  6. {  
  7.     NSLog(@"%@ is flying"self.name);  // 这里通过self存取方法,获得Car类的name属性值  
  8. }  
  9. @end  

上面的代码值得注意的一点是,fly函数通过self方式取得了name属性,这里其实表明分类对于类属性的访问,其实是和类本身定义一样的。(但不能够通过_name属性名称直接访问属性,否则会提示未定义)。这一点同继承不同(属性对于子类是不可见的,子类只能通过继承得到的存取方法访问属性)。

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

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

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

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

Car.h,没有对fire的声明

[objc]  view plain  copy
  1. @interface Car : NSObject  
  2. @property(nonatomicstrong)NSString* name;  
  3. @property(nonatomicgetter=leftGas) NSUInteger totalGas;  
  4.   
  5. -(instancetype)initWithName:(NSString*) name;  
  6.   
  7. -(void) run;  
  8. -(void) addGas:(NSUInteger) gas;  
  9. @end  

Car.m 直接实现没有声明过的fire方法,该方法在类外部不可见,但类中可以通过[self fire]形式调用 

[objc]  view plain  copy
  1. @implementation Car  
  2. ....  
  3. -(void) fire  
  4. {  
  5.     NSLog(@"%@ fire!"self.name);  
  6. }  
  7. ....  
  8. @end  

那么对于fire方法,在分类fly中是无法调用到的,若调用该方法,则会提示未定义的错误

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

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

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

[objc]  view plain  copy
  1. 类名+分类名.h/.m  

例如,对于Car的fly分类,我们应该命名文件

[objc]  view plain  copy
  1. Car+fly.h  
  2. Car+fly.m  

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

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


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

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

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

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


类扩展

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

[objc]  view plain  copy
  1. @interface Car ()  
  2. -(void) fire;  
  3. @property(nonatomic) NSUInteger price;  
  4. @end  

括号中并未给出分类名称,这种分类有个专业名称—— 类扩展

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

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

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

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


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

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

2、分类扩展可以继承。

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

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

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


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


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OC中的分类与类扩展 的相关文章

  • Mac 上使用 Mono 的 mkbundle:找不到“mono/metadata/mono-config.h”文件

    我正在尝试使用 Mono 创建 Mac 捆绑包 当我执行时 mkbundle file exe deps o FILE 我在编译过程中得到这个 fatal error mono metadata mono config h file not
  • OSX:从命令行检查屏幕是睡眠还是唤醒

    有什么方法可以通过命令行或 applescript 检查屏幕是否处于睡眠状态或唤醒状态 与此相关 检查 Applescript 中显示器是否处于休眠状态 https stackoverflow com questions 32319778
  • 检查 u 键是否被按下 Swift Cocoa [重复]

    这个问题在这里已经有答案了 我正在尝试检测是否U键是否被按下 如果是的话应该print BUT BUT 但我不确定如何检查不同的按键 因为按键的文档非常糟糕 我找到了带有键码的答案 但它们仅适用于 QWERTY 键盘 视图控制器 swift
  • 为什么我无法在 OS X 上更改 tkMessagebox.askyesno() 上的图标?

    tkMessageBox askyesno Title Message icon tkMessageBox WARNING 在 OS X 上只给我火箭图标 我知道 OS X 和 tkMessageBox 图标有些奇怪 因为tkMessage
  • AppleScript:如何获取文件夹中没有隐藏文件的文件?

    我其实有两个问题 当我尝试获取文件夹中的文件时 如何排除 DS STORE Icon 等隐藏文件 我试过了 没有隐形人 但似乎不起作用 如果已经存在 如何将我的 var the new folder 设置为现有文件夹 感谢您的回答 My c
  • CakePHP:无法访问 MySQL 数据库

    我是 CakePHP 的新手 刚刚完成配置过程 但很困惑为什么 Cake 无法访问我的 MySQL 数据库 Cake 信息页面显示我的 tmp 目录是可写的 FileEngine 正在用于缓存 不知道这意味着什么 并且我的数据库配置文件存在
  • 在 MacOS 上重新启动终端而不关闭

    如何在不关闭窗口的情况下重新启动当前的 MacOS 终端会话 在Linux中我使用exec bash但在这种环境下它不起作用 我对 bash profile 提示 别名等 我想在不关闭它并再次打开的情况下查看 只需输入命令 exec bas
  • 如何在 mac os 10.6 上安装brew或homebrew

    我已经尝试过多次了 谁能告诉我具体的详细步骤吗 我的Mac操作系统是10 6 8 它抱怨一些丢失的包裹 使用它在 Mac OSX 10 6 8 上安装 ruby e curl fsSL https raw githubusercontent
  • 从内存加载动态库

    是否可以从内存而不是从 mac gcc 上的文件系统加载库 在 Windows 中 我使用 MemoryModule 但它显然不跨平台兼容 首先 要做到这一点 我建议您阅读OS X ABI 动态加载器参考 https developer a
  • 使 pycaffe 致命错误:找不到“Python.h”文件

    我在运行 OSX 10 9 5 的 Mac 上编译了 caffe 并且我知道尝试编译 pycaffe 当我在 caffe 根文件夹中运行 make pycaffe 时 我得到 CXX LD o python caffe caffe so p
  • 在 Mac 上运行 Tkinter

    我是一个绝对的新手 我正在尝试为我的学校项目制作 Python GUI 所以我决定使用 Tkinter 当我尝试导入 Tkinter 时 它会抛出以下消息 gt gt gt import tkinter Traceback most rec
  • Mac OS X 上的 Qt 字体系列和样式

    我有一个基于 Qt PyQt 的 GUI 应用程序 在 Mac OS X 和其他平台 上运行 它允许用户选择字体并具有粗体和斜体选项的复选框 在更新到新的基于 Cocoa 的 Qt 时 用户发现QFontComboBox不再显示不同的字体样
  • 在 MacOS 上的 AdoptOpenJDK 上链接 JNA 库时出错

    我正在尝试在 cassandra 上运行一些 JUnit 测试 但我收到以下错误 08 12 19 10 48 40 411 main INFO c h c c e EmbeddedCassandra Starting embedded C
  • SwiftUI:获取动态背景颜色(深色模式或浅色模式)

    有没有一种方法可以系统地访问 SwiftUI 视图的标准动态背景颜色 无论用户处于浅色模式还是深色模式 例如 我知道以下内容可用于获取主要 例如文本 颜色 let textColor Color primary 但我没有看到任何类似的背景颜
  • 如何在 Mac 上使用 Process.Start() 或等效的 Mono 并传入参数

    我正在尝试编写一些 C 代码来启动浏览器Process Start app args 其中 apps 是浏览器的路径 例如 Applications Google Chrome app Contents MacOS Google Chrom
  • QFileSystemModel setRootPath

    我正在尝试创建一个 Qt 应用程序来显示文件夹 Mac OS 中的 Users 文件夹 的内容 这是代码 QFileSystemModel dirModel new QFileSystemModel dirModel gt setRootP
  • NSSharingService 共享子菜单

    如何在 Mac 应用程序中添加共享子菜单 例如 Safari gt 文件 gt 共享 我戳了戳Apple 共享服务示例代码 http developer apple com library mac samplecode SharingSer
  • 卸载我安装的所有 Python 包及其依赖项,而不用破坏我的 Mac

    有很多问题 但正确的方法似乎是手动卸载不需要的所有内容 pip 在卸载时不会卸载包的依赖项 https stackoverflow com questions 7915998 does uninstalling a package with
  • 如何将 UILabel 的值绑定到实例变量?

    我是 mac objective c 的新手 我的问题是 我想知道是否可以将 UILabel 文本绑定到变量 而不必在值更改时手动设置文本 例如 在 Mac OS 上 当我打开新的 Finder 窗口并删除文件时 任务栏中的全局可用空间就会
  • 在 Mac 操作系统上使用 ffmpeg 录制视频

    我想在 mac OS 上使用 ffmpeg 以任何格式录制实时网络摄像头视频 我尝试了很多 但无法找到用于重新编码视频的命令 所以请任何人都可以告诉我 ffmpeg 命令用于使用 Mac 操作系统的网络摄像头捕获视频 提前致谢 对于 Mac

随机推荐

  • 手机APP远程温湿度监控系统(连上公网、阿里云)

    APP界面 实物图 操作演示 一 硬件电路图 这里有两点需要说明 1 第一点是关于LCD1602需不需要加上拉电阻的说明 51单片机P0口作为IO口输出时 输出低电平为0 输出高电平为高组态 并非5V 相当于悬空状态 也就是说P0 口不能真
  • 【蓝桥杯Python组】寻找2020

    寻找2020 题目描述 小蓝有一个数字矩阵 里面只包含数字 0 和 2 小蓝很喜欢 2020 他想找到这个数字矩阵中有多少个 2020 小蓝只关注三种构成 2020 的方式 同一行里面连续四个字符从左到右构成 2020 同一列里面连续四个字
  • matlab中 hold on 与 hold off,figure作用

    hold on是当前轴及图像保持而不被刷新 准备接受此后将绘制的图形 多图共存 即启动图形保持功能 当前坐标轴和图形都将保持 从此绘制的图形都将添加在这个图形的基础上 并自动调整坐标轴的范围 hold off使当前轴及图像不再具备被刷新的性
  • moviepy音视频剪辑:视频剪辑基类VideoClip详解

    前往老猿Python博文目录 一 概述 在 moviepy音视频剪辑 moviepy中的剪辑基类Clip详解 和 moviepy音视频剪辑 moviepy中的剪辑基类Clip的属性和方法详解 介绍了剪辑相关类及类关系 可以看到视频剪辑类Vi
  • 汽车电子行业静态分析和代码审查规则

    汽车电子行业静态分析和代码审查规则 查了很多编码规则大都是PDF版 最终我整理出了几份word版的 并且帮大家排版好了可直接用于书写测试大纲或报告 下载链接在我的下载中 规则包含以下 1 MISRA C 2012 2 MISRA C 200
  • Node.js入门 03:模块化规范 CommonJS 与 ES Module

    文章目录 目的 CommonJS 基础使用 module 对象 require 方法 ES Module 混合使用 总结 目的 传统的用在网页中的JavaScript代码文件与文件之中的内容都是全局相互可见的 这对于大型项目特别是多人合作的
  • 领域驱动设计:DDD分层架构

    文章目录 DDD 分层架构 DDD 分层架构最重要的原则 DDD 分层架构推动架构演进 三层架构如何演进到 DDD 分层架构 微服务架构模型有好多种 例如整洁架构 CQRS 和六边形架构等等 每种架构模式虽然提出的时代和背景不同 但其核心理
  • 近一月翻阅资料小结

    近一个月接触的东西比较多 梳理一下 Nginx Tomcat 实现负载均衡 同时采用keepalived的形式实现HA 负载后 关键问题就是session共享的问题 可实现的思路较多 Tomcat6以后本身可以使用cluster技术达成 也
  • 训练自己的ai模型(三)学习笔记与项目实操(一些概念理解杂谈)

    ai模型大火 作为普通人 我也想做个自己的ai模型 训练自己的ai模型通常需要接下来的的六步 一 收集和准备数据集 需要收集和准备一个数据集 其中包含想要训练模型的数据 这可能需要一些数据清理和预处理 以确保数据集的质量和一致性 二 选择和
  • PTA——7-3 两个数的简单计算器

    输入格式 输入整数A 符号ch和整数B 输出格式 根据符号ch 在一行中输出A ch B的值 如果ch是 则输出A B的值 如果ch是 则输出A B的值 如果ch是 则输出A B的值 如果ch是 则输出A B的值 题目保证B不为0 并且结果
  • C++泛型编程:源起、实现与意义

    C 泛型编程 源起 实现与意义 为什么泛型泛型编程 Generic Programming 最初提出时的动机很简单直接 发明一种语言机制 能够帮助实现一个通用的标准容器库 所谓通用的标准容器库 就是要能够做到 比如用一个List类存放所有可
  • [Linux]日志文件已删掉磁盘空间不释放,不重启服务进程的解决方法

    Linux 日志文件已删掉磁盘空间不释放 不重启服务进程的解决方法 问题背景 服务进程启动后 后台会有写日志的操作 当服务进程还没停掉 日志就会一直在写 这时候手动删除日志 会造成日志在linux该目录下已经删除 但是磁盘空间不会被释放掉
  • C语言函数操作大全----(超详细)

    fopen 打开文件 相关函数 open fclose 表头文件 include
  • MAC电脑常用效率工具推荐

    作者主页 IT技术分享社区 作者简介 大家好 我是IT技术分享社区的博主 从事C Java开发九年 对数据库 C Java 前端 运维 电脑技巧等经验丰富 个人荣誉 数据库领域优质创作者 华为云享专家 阿里云专家博主 个人博客 IT技术分享
  • supervisor系列:3、配置文件

    supervisor系列 3 配置文件 文章目录 supervisor系列 3 配置文件 1 文件格式 1 1 环境变量 2 unix http server 段设置 2 1 unix http server 段的值 2 2 unix ht
  • VS中Qt中ui文件和生成.h文件问题

    vs中的ui的ui xxxx h头文件是由Qt通过编译生成 vs项目属性中配置环境调用Qt安装目录下bin目录下的uic exe来自动生成代码 如果移动工程目录 而之前又把相关的ui xxx h头文件添加到工程或移动其位置 那么再次修改ui
  • sketchup 255个su常用插件)_「教程」巧用Rhino和SU,做出你想要的地形效果

    Xiao素材 地形建模教程 本期精选 教你如何做好地形效果图 1 SU部分 地形效果 SU插件安装小教程 su软件是我们现在经常会使用到的一个软件 但是在我们作图的过程中会发现 很多情况下 相对于一些复杂的图形我们需要依赖相关的插件 比如
  • python递归函数代码_Python递归函数 二分查找算法实现解析

    一 初始递归 递归函数 在一个函数里在调用这个函数本身 递归的最大深度 998 正如你们刚刚看到的 递归函数如果不受到外力的阻止会一直执行下去 但是我们之前已经说过关于函数调用的问题 每一次函数调用都会产生一个属于它自己的名称空间 如果一直
  • Kubernetes + Dashboard 集群搭建

    1 环境说明 基于kubeadm工具部署k8s 集群 还有基于二进制的部署方式但是需要单独部署k8s的每个组件比较繁琐 kubeadm是 Kubernetes官 提供的 于快速部署Kubernetes集群的 具 基于Kubernetes v
  • OC中的分类与类扩展

    在OC中 对于已有的类进行扩展 我们有两种方式 1 在原始类的定义中 进行代码扩展 2 通过继承的方式 扩展子类 3 使用分类的方式 第一 二种方式不用多说 第三种方式则是OC中比较有特色的功能 分类允许我们在不更改类的原始代码的情况下 实