ObjectiveC-10-OOP面向对象程序设计-分类/类别

类别(Category)是OjectiveC的一个特性,主要目的是让开发者可以以模块的形式向类添加方法(扩展),创建标准化的方法列表供给其他人实现。

有些文档也会翻译成类别,其实是一个意思。

概述

语法说明

类别提供了一个简单的方式,将类定义模块化到相关组或分类中,同时也提供了扩展现有类定义的简便方式。换句话说,它的功能有些类似于接口继承,但又比继承简单和强大,在使用时需要结合继承一起使用,其能力是非常厉害的。 分类的语法如下:

@interface Fraction(Category1) //类名+(类别名称)
 //分类方法的代码
@end
@interface Fraction(Category2)
 //分类方法的代码
@end

类别的作用

如果在xcode中使用新建文件功能创建Cocoa class文件,会自动生成.h和.m文件。在这种分离的设计基础上附加分类后,可以使用分类实现下面三个方面的能力增强:

  1. 扩展现有类库的功能:比如扩展NSString、NSObject类,这种方式某些书中扩展NSObject类有时被称为非正式协议;
  2. 扩展现有类的声明:定义一个声明,然后分模块实现,比如在一个.h文件中定义类声明,然后分多个.m实现,一个.m实现其中一个分类,这样方便分工合作;
  3. 为现在的自定义类添加私有方法而不必重新定义子类;

类别规则

  1. 类别文件名称一般是是“类名称+类别名称”来命名,这是一个不成文的规定;
  2. 类别中可以添加属性,但不能添加实例变量,而且属性必须是@dynamic类型的;
  3. 如果类别方法与现有类的方法重名,类的方法会被覆盖掉,一旦覆写后外部就不能访问原来的方法了,所以这块要特殊设计一下;
  4. 如果多个分类中有同名的方法,可能会引起混乱;分类后不仅会影响当前类,也会影响所有的子类;
  5. 类别的名称是在类的范围内是唯一的;

创建类别

在新建文件中,选择Objective-C文件类型
在这里插入图片描述
在配置界面做如下配置,注意File Type选择 Category:
在这里插入图片描述
最后生成如下项目工程文件如下:
在这里插入图片描述

类别能力

给现有类添加新方法

类别可以为所有类添加新方法,包括系统类库和自定义的类。下面的代码就用一个自定义的类别来扩展系统提供的NSString类库的功能。

  • 类别定义
//扩展系统NSString,添加一个名为NumberConvenience的类别
#import <Foundation/Foundation.h>

@interface NSString (NumberConvenience)

- (NSNumber *)lengthAsNumber; //添加一个新方法

@end

  • 类别实现
#import "NSString+NumberConvenience.h"

@implementation NSString (NumberConvenience)

- (NSNumber *)lengthAsNumber{
    NSUInteger length = [self length];
    return ([NSNumber numberWithUnsignedInt:length]);
} // lengthAsNumber

@end
  • 类别测试
#import <Foundation/Foundation.h>
#import "NSString+NumberConvenience.h"

int main(int argc, const char * argv[]){
    @autoreleasepool
    {
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setObject:[@"hello" lengthAsNumber] forKey:@"hello"];
        NSLog (@"%@", dict);
    }
    return 0;
}

类能力(声明)的动态扩展

有别于上面的给现有类添加新方法的实现,类功能的动态扩展不需要新建文件,也可以实现定义实例变量。

方法是创建一个未命名的分类,然后在()中不指定任何名字,在这个类中可以扩展实例变量和属性(在有命名的分类中是不允许的)。未命名分类中的方法需要在主实现区中实现,而不是在分离的实现区中实现。

在未命名类别中的扩展的属性必须是私有的

  • 自定义类,Fraction是一个自定义的类,用于此示例的测试
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

//原始接口声明
@interface Fraction : NSObject

@property (assign) NSInteger thing1;
//标记为只读属性
@property (readonly, assign) NSInteger thing2;

- (void)resetAllValues;

@end
  • 扩展自定义类的属性和方法
@interface Fraction() //空
NS_ASSUME_NONNULL_END
{
    NSInteger thing4; //添加了新实例变量
}
@property (readwrite, assign) NSInteger thing2; //覆盖了原有属性
@property (assign) NSInteger thing3; //添加了新私有属性
@end
  • 实现自定义类
#import "Fraction.h"

@implementation Fraction

- (void)resetAllValues
{
    self.thing1 = 200;
    self.thing2 = 300;
    self.thing3 = 400;
    thing4 = 5;
}

- (NSString *) description
{
    NSString *desc = [NSString stringWithFormat: @"%d %d %d %d", _thing1, _thing2, _thing3, thing4];
    
    return (desc);
    
} // description

@end
  • 测试代码
#import <Foundation/Foundation.h>
#import "NSString+NumberConvenience.h"
#import "Fraction.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        
        [dict setObject:[@"hello" lengthAsNumber] forKey:@"hello"];
        
        NSLog (@"%@", dict);
        
        
        Fraction *things = [[Fraction alloc] init];
        things.thing1 = 1;
        NSLog(@"%@", things); //~1 0 0 0
         
        //重新赋值
        [things resetAllValues];
        NSLog(@"%@", things); //~200 300 400 5
    }
    return 0;
}

类分文件实现

前面所有的代码实现全是一个.h,一个m。如果是大型项目的话.m中的代码量可能非常区大,这里可以采用两种不同的设计方案解决:拆类或是分类。除了代码整洁外,还可以多人协作以及实现代码分包存储等功能,打破了继承这种约束。
在这里插入图片描述

即定义一个.h,多个.m实现这样的模式来分散类的实现,每个.m实现一个类别接口,示例代码如下:

类别定义

在这里插入图片描述

//类别定义
#import <Foundation/Foundation.h>

@interface CategoryThing : NSObject
{
  NSInteger thing1;
  NSInteger thing2;
  NSInteger thing3;
}
@end // CategoryThing

// Category thing1
@interface CategoryThing (Thing1)
- (void)setThing1:(NSInteger)thing1;
- (NSInteger)thing1;
@end

// Category thing2
@interface CategoryThing(Thing2)
- (void)setThing2:(NSInteger)thing2;
- (NSInteger)thing2;
@end // CategoryThing (Thing2)

// Category thing3
@interface CategoryThing (Thing3)
- (void)setThing3:(NSInteger)thing3;
- (NSInteger)thing3;
@end // CategoryThing (Thing3)

类别实现

在这里插入图片描述

#import "CategoryThing.h"

@implementation CategoryThing (Thing1)
- (void)setThing1:(NSInteger)t1{
    thing1 = t1;
}

- (NSInteger) thing1{
    return (thing1);
}

@end // CategoryThing
#import "CategoryThing.h"

@implementation CategoryThing (Thing2)

- (void)setThing2:(NSInteger) t2{
    thing2 = t2;
}

- (NSInteger)thing2{
    return (thing2);
}

@end 
\#import "CategoryThing.h"

@implementation CategoryThing (Thing3)

- (void)setThing3:(NSInteger) t3{
    thing3 = t3;
}

- (NSInteger)thing3{
    return (thing3);
}

@end 

程序测试

main测试

#import <Foundation/Foundation.h>
#import "CategoryThing.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        CategoryThing *thing = [[CategoryThing alloc] init];
        
        [thing setThing1: 5];
        [thing setThing2: 23];
        [thing setThing3: 42];
        
        NSLog (@"Things are %@", thing); //Things are 5 23 42
    }
    return 0;
}

end…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/519438.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue3从入门到实战:掌握状态管理库pinia(下部分)

1.storeToRefs 在Count.vue文件中 显的冗余了&#xff0c;如何更加优雅简化代码。用storeToRefs 补充&#xff1a; 为什么不用ToRefs呢&#xff1f; 使用的话会将所有数据都用ref引用包裹&#xff0c;其实方法等是没必要包裹的&#xff0c;具有一定风险 2.getters的使用 …

使用Arcpy进行数据批处理-批量裁剪

时空大数据使我们面临前所未有的机遇和挑战&#xff0c;尤其在地学、遥感或空间技术等专业领域&#xff0c;无疑是一个全新的时代。 伴随着时空大数据的到来&#xff0c;海量数据的处理是一个所有科研工作者都无法忽视的重要问题。传统的数据&#xff08;主要指空间数据&#x…

选择企业邮箱,扬帆迈向商务新纪元!

企业邮箱和个人邮箱不同&#xff0c;它的邮箱后缀是企业自己的域名。企业邮箱供应商一般都提供手机app、桌面端、web浏览器访问等邮箱使用途径。那么什么是企业邮箱&#xff1f;如何选择合适的企业邮箱&#xff1f;好用的企业邮箱应具备无缝迁移、协作、多邮箱管理等功能。 企…

后端开发框架Spring Boot快速入门

写在前面 推荐将本文与Spring Boot 相关知识和工具类一文结合起来看&#xff0c;本文为主&#xff0c;上面那篇文章为辅&#xff0c;一起食用&#xff0c;以达到最佳效果&#xff0c;当然&#xff0c;大佬随意。 IDEA创建Spring Boot工程 关于Spring Boot框架项目&#xff0…

Go协程池gopool源码解析

1、gopool简介 Repository&#xff1a;https://github.com/bytedance/gopkg/tree/develop/util/gopool gopool is a high-performance goroutine pool which aims to reuse goroutines and limit the number of goroutines. It is an alternative to the go keyword. gopool的…

数的基础概念

数的基本概念 结点 每一个圆圈就表示一个结点&#xff0c;每个结点里而会存放一些数据(点权值) 边 连接两个结点的一条线&#xff0c;我们认为上面的是父亲&#xff0c;下面的是儿子&#xff0c;边也可以存储权值(边权)。在树中&#xff0c;边的条数严格等于点…

探索未来智慧酒店网项目接口架构

在数字化时代&#xff0c;智慧酒店已成为酒店业发展的重要趋势之一。智慧酒店网项目接口架构作为支撑智慧酒店运营的核心技术之一&#xff0c;其设计和优化对于提升用户体验、提高管理效率具有重要意义。本文将深入探讨智慧酒店网项目接口架构的设计理念和关键要素。 ### 智慧…

备战蓝桥杯---线段树应用2

来几个不那么模板的题&#xff1a; 对于删除&#xff0c;我们只要给那个元素附上不可能的值即可&#xff0c;关键问题是怎么处理序号变化的问题。 事实上&#xff0c;当我们知道每一个区间有几个元素&#xff0c;我们就可以确定出它的位置&#xff0c;因此我们可以再维护一下前…

Unity 代码控制播放序列帧动画的实现

在Unity中有些应用场景的动画是通过序列帧实现的。 如下图即为一个英雄攻击的一个动画&#xff1a; 那么如何实现该序列帧动画的播放呢&#xff0c;我们可以通过代码来控制播放。 1、把以上序列帧导入编辑器中&#xff0c;并修改图片属性&#xff0c;如下图所示&#xff0c;其…

利用Idea实现Ajax登录(maven工程)

一、新建一个maven工程&#xff08;不会建的小伙伴可以参考Idea引入maven工程依赖(保姆级)-CSDN博客&#xff09;&#xff0c;工程目录如图 ​​​​​​​ js文件可以上up网盘提取 链接&#xff1a;https://pan.baidu.com/s/1yOFtiZBWGJY64fa2tM9CYg?pwd5555 提取码&…

UI自动化测试重点思考(上)--元素定位/验证码/测试框架

UI自动化测试重点思考--元素定位 Selenium定位元素selenium中如何判断元素是否存在&#xff1f;定位页面元素webdriver打开页面id定位name定位class_name定位tag_name 定位xpath定位css_selector定位link_text 定位partial_link 定位总结 selenium中元素定位的难点&#xff1f;…

K8S - Deployment 的版本回滚

当前状态 先看deployment rootk8s-master:~# kubectl get deploy -o wide --show-labels NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES …

武汉星起航:深耕全球市场,拓展国际影响力,共赢未来跨境新篇章

在瞬息万变的跨境电商领域&#xff0c;武汉星起航凭借其敏锐的创新意识和卓越的执行力&#xff0c;为行业注入了新的活力。作为一家追求卓越、勇于创新的企业&#xff0c;武汉星起航深知创新是成功的关键。公司通过不断探索新的商业模式、引入先进技术和优化运营流程&#xff0…

【pycharm】在debug循环时,如何快速debug到指定循环次数

【pycharm】在debug循环时&#xff0c;如何快速debug到指定循环次数 【先赞后看养成习惯】求关注收藏点赞&#x1f600; 在 PyCharm 中&#xff0c;可以使用条件断点来实现在特定循环次数后停止调试。这可以通过在断点处右键单击&#xff0c;然后选择 “Add Breakpoint” -&g…

【精品教程】护网HVV实战教程资料合集(持续更新,共20节)

以下是资料目录&#xff0c;如需下载&#xff0c;请前往星球获取&#xff1a; 01-HW介绍.zip 02-HTTP&Burp课程资料.zip 03-信息收集_3.zip 04-SQL注入漏洞_2.zip 05-命令执行漏洞.zip 06-XSS漏洞.zip 07-CSRF.zip 08-中间件漏洞.zip 09-SSRF.zip 10-XXE.zip 11-Java反序列…

2024 最新版 Proteus 8.17 安装汉化教程

前言 大家好&#xff0c;我是梁国庆。 今天给大家带来的是目前 Proteus 的最新版本——Proteus 8.17。 时间&#xff1a;2024年4月4日 获取 Proteus 安装包 我已将本篇所使用的安装包打包上传至百度云&#xff0c;扫描下方二维码关注「main工作室」&#xff0c;后台回复【…

Netty客户端发送数据给服务器的两个通道(1)

EventLoopGroup group new NioEventLoopGroup();// 设置的连接group。 Bootstrap bootstrap new Bootstrap().group(group).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) // 超时时间。 .channel(NioSocketChannel.class).handler(new ChannelInitializer() { Ov…

【stm32】I2C通信协议

【stm32】I2C通信协议 概念及原理 如果我们想要读写寄存器来控制硬件电路&#xff0c;就至少需要定义两个字节数据 一个字节是我们要读写哪个寄存器&#xff0c;也就是指定寄存器的地址 另一个字节就是这个地址下存储寄存器的内容 写入内容就是控制电路&#xff0c;读出内容就…

vue 浅解watch cli computed props ref vue slot axios nexttick devtools说明使用

Vue.js 是一个强大的前端框架&#xff0c;它提供了很多有用的功能和工具。你提到的这些特性&#xff08;watch、cli、computed、props、ref、slot、axios、nextTick、devtools&#xff09;在 Vue 中各自扮演着不同的角色。下面我会逐一解释这些特性如何在 Vue 中使用&#xff1…

蓝桥杯每日一题:约数个数(质因数)

题目描述&#xff1a; 输入 n 个整数&#xff0c;依次输出每个数的约数的个数。 输入格式 第一行包含整数 n。 第二行包含 n 个整数 ai。 输出格式 共 n 行&#xff0c;按顺序每行输出一个给定整数的约数的个数。 数据范围 1≤n≤1000, 1≤ai≤10^9 输入样例&#xff…