分类(category)的使用
首先可以查看下官方对于Category的介绍:Apple官方文档解释
个人理解:
- Category初衷是用来给现有类添加或者重写函数的,不可添加属性,这个区别于Extension;
- 将类的一些类似的功能拆分出去,使得每个分类中的函数功能统一,便于管理;
- 给系统类(NSString,NSArray等)添加一些自定义的方法;
- 重写私有类的函数(公有、私有均可),改变内部的实现代码。
另类使用:
- 因为Category是不具有属性列表的,所以不能给Category添加属性。那怎么通过@property给定义的Catogory添加属性呢?接下来就详细讲解:
定义一个NSObject的分类Worker,通过@property声明两个属性如下:
@interface NSObject (Worker)
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *jodName;
@end
如果这时直接使用name和jodName如下:
NSObject *worker = [[NSObject alloc] init];
worker.name = @"Jim";
worker.jodName = @"Software Engineer";
command+R运行则会报如下错误:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSObject setName:]: unrecognized selector sent to instance 0x600001a7c570'
这是因为系统不会给Category添加属性的setter/getter方法,所以这时就要用到runtime机制了,写法如下:
// name的key
static NSString *keyName;
// jobName的key
static NSString *keyJobName;@implementation NSObject (Worker)
- (void)setName:(NSString *)name {objc_setAssociatedObject(self, &keyName, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {return objc_getAssociatedObject(self, &keyName);
}
- (void)setJodName:(NSString *)jodName {objc_setAssociatedObject(self, &keyJobName, jodName, OBJC_ASSOCIATION_COPY);
}
- (NSString *)jodName {return objc_getAssociatedObject(self, &keyJobName);
}
@end
在 setter 里面使用了一个 objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy) 方法,这个方法有四个参数,分别是:
- 源对象(self)
- 关联时的用来标记是哪一个属性的key (keyName,keyJobName)
- 关联的对象(name、jobName)
- 一个关联策略(OBJC_ASSOCIATION_COPY)
在 getter 里面用到了 objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key) 这个方法,这个方法有两个参数,填写方法参照setter方法。
这时再运行代码如下:
NSObject *worker = [[NSObject alloc] init];
worker.name = @"Jim";
worker.jodName = @"Software Engineer";
NSLog(@"Hello, my name is %@, I am a %@ !",worker.name,worker.jodName);
打印信息如下:
2019-04-30 11:24:43.258099+0800 test[44759:2009573] Hello, my name is Jim, I am a Software Engineer !
这样就实现了在变相的在分类里添加了假属性,注意:这种添加方式并不支持_name和_jobName的方式调用方式,因为真正意思上并没有相关属性
- 重写类的方法,并介绍如何调用原类方法:
在分类中重写了原类中的方法,在调用该方法时,程序是触发的分类中重写的方法,但有时我们还是需要用到原类中的方法,接下来就看下怎么用代码实现:
先生成一个Person类,实现一个方法:
- (NSString *)getWorkerIntroducation {return @"该方法由分类实现的,返回的是这个人的介绍信息";
}
在生成一个分类Person+Worker.h,重写方法如下:
- (NSString *)getWorkerIntroducation {if (self.name.length&&self.jodName.length) {return [NSString stringWithFormat:@"My name is %@, I am a %@!", self.name, self.jodName];} else {return nil;}
}
在调用如下:
Person *worker = [[Person alloc] init];
worker.name = @"Jim";
worker.jodName = @"Software Engineer";
NSLog(@"%@", [worker getWorkerIntroducation]);
打印日志:
2019-04-30 15:59:05.812732+0800 test[46479:2079803] My name is Jim, I am a Software Engineer!
根据分类的原理,结构体中存在一个对象方法列表,主要就是通过获取方法的列表实现调用原类的方法,我们可以先打印一下对象方法列表:
Person *worker = [[Person alloc] init];
worker.name = @"Jim";
worker.jodName = @"Software Engineer";
NSLog(@"%@", [worker getWorkerIntroducation]);// 打印对象方法列表
u_int count;
Method *methods = class_copyMethodList([worker class], &count);
for (int i=0; i<count; i++) {SEL sel = method_getName(methods[i]);NSString *methodName = [NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding];NSLog(@"%d = %@", i, methodName);
}
// 打印结果
// 调用分类重写方法
My name is Jim, I am a Software Engineer!
0 = setJodName:
// 分类的重写方法
1 = getWorkerIntroducation
// 原类的重写方法
2 = getWorkerIntroducation
3 = jodName
4 = name
5 = setName:
从打印信息来看分类的调用优先级是在前面的,所以需要遍历获取最后的方法再通过IMP调用,代码如下:
Person *worker = [[Person alloc] init];
worker.name = @"Jim";
worker.jodName = @"Software Engineer";
NSLog(@"%@", [worker getWorkerIntroducation]);// 打印对象方法列表
u_int count;
Method *methods = class_copyMethodList([worker class], &count);
int index = -1;
for (int i=0; i<count; i++) {SEL sel = method_getName(methods[i]);NSString *methodName = [NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding];if ([methodName isEqualToString:@"getWorkerIntroducation"]) {index = i;}
}
if (index>=0) {// 通过index获取原类的方法SEL sel = method_getName(methods[index]);IMP imp = method_getImplementation(methods[index]);NSString *string = ((id (*)(id, SEL)) imp)(self, sel);NSLog(@"%@",string);
} else {NSLog(@"不存在该方法");
}
打印结果:
// 执行的分类方法
2019-04-30 17:21:50.688067+0800 test[49470:2130743] My name is Jim, I am a Software Engineer!
// 执行的原类方法
2019-04-30 17:21:50.688238+0800 test[49470:2130743] 该方法由分类实现的,返回的是这个人的介绍信息
代码传送门:
- 样例代码
传送门:
- IMP原理介绍
- Category底层实现原理小记
分类(category)的使用相关推荐
- iOS之深入解析分类Category的底层原理
一.Category 简介 Objective-C 中的 Category 是对装饰模式的一种具体实现.它的主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法. 分类 Category 可以 ...
- Objective-C分类 (category)和扩展(Extension)
1.分类(category) 使用Object-C中的分类,是一种编译时的手段,允许我们通过给一个类添加方法来扩充它(但是通过category不能添加新的实例变量),并且我们不需要访问类中的代码就可以 ...
- oc的分类category
category分类,指的是可以将类无尽的拓展起方法,是不能拓展属性的.类名后面有个括号代表这个类是分类eg: #import "Student.h" @interface Stu ...
- WordPress插件:WP No Category Base 去除分类Category目录
不少折腾WordPress的朋友都希望去掉分类链接中的 /category/ 目录标志,网上很多这方面的教程,据倡萌所知,除了使用 WP No Category Base 插件(或类似插件),其他的方 ...
- category显示html,wordpress文章.html伪静态,分类category和页面设置 - 搜外SEO问答
最近把网站文章整顿了一番,将所有文章都伪静态了一番.文章统一增加html后缀,并且分类去掉了category,页面增加了html. 1,所有所有分类目录去掉category,安装WP No Categ ...
- ios 分类(Category)
今天研究了类别,都是网上找的资料,类别的作用 类别主要有3个作用: (1)将类的实现分散到多个不同文件或多个不同框架中. (2)创建对私有方法的前向引用. ...
- OC特有语法:分类category,给NSString增加方法计算字符串中数字的个数
1:分类的使用场景:想对一个类,扩充一些功能,而又不改变原来类的模型,也不用继承,这时OC中的特有语法:分类可以做到: 当然分类也是一个类,也需要声明和实现,声明在.h文件中,实现在.m文件中,格式如 ...
- woocommerce 分类到菜单_Woocommerce教程:添加和编辑产品Category分类
在使用WordPress的woocommerce商城插件制定商城的时候, 如果你公司拥有众多产品, 那么应该需要给这些产品添加Category分类, 以便分类管理产品, 让网站访客更快地找到自己想要的 ...
- oc 协议 回调 静态成员_OC底层原理探究:Category、关联对象和block本质
1.分类Category的使用 // 给MJPerson类添加分类 @interface MJPerson : NSObject - (void)run; @end@implementation MJ ...
- (iOS-基本知识)Category VS Extension 原理详解
1.什么是Category? category是Objective-C 2.0之后添加的语言特性,别人口中的分类.类别其实都是指的category.category的主要作用是为已经存在的类添加方法. ...
最新文章
- 学了python能干啥-python都可以做什么用
- Linux常用命令——paste
- 【TDS学习文档4】IBM Directory schema的管理2——object class
- 如何使用Angular的@Input()装饰器
- 关灯看视频(Turn Off the Lights)
- [蓝桥杯2019初赛]矩形切割-找规律
- QQ音乐:React v16 新特性实践
- 泉州中考分数如何计算机,2019年泉州中考总分多少分,泉州中考考试科目设置
- QItemSelectionModel——视图选择
- Pycharm在创建py文件时, 如何自动添加文件头注释?
- PyQt5教程 - QtDesigner窗口设计工具的使用
- 桌面计算机恢复出厂设置,windows7电脑怎么恢复出厂设置
- Hbuilder连接苹果手机
- 分享老齐【学方法】宽信用周期对股市的影响!
- 5G路测下行速率优化指导书
- python--快速启动Server
- 基于ZigBee的出租车调度系统
- 移动端图片变模糊问题
- 企业级监控系统zabbix---通过qqmail发送告警信息
- Comet OJ - Contest #10 沉鱼落雁