objectiveC中Category分类你知多少
在OC 中,使用category会让我们在开发中非常方便,可以为某个类增添方法,对类别自己有一点小小的体会,首先先来介绍一下类别1.分类的创建:
1.类别的作用
(1)可以将类的实现分散到多个不同的文件或者不同的框架中,方便代码的管理。也可以对框架提供类的扩展(没有源码,不能修改)。
(2)创建对私有方法的前向引用:如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告
(3)向对象添加非正式协议:创建一个NSObject的类别称为"创建一个非正式协议",因为可以作为任何类的委托对象使用。
2.局限性
(1)分类只能增加方法,不能增加成员变量,但是可以通过运行时来给分类添加属性,那么成员变量和属性有什么区别呢?
(2)如果分类和原来类出现同名的方法, 优先调用分类中的方法,原来类中的方法会被忽略,方法调用的优先级(从高到低) 分类(最后参与编译的分类优先),只要有分类就优先调用分类,不考虑与主类的编译顺序
(3)方法的调用优先级:分类-->原来的类-->父类,若包含多个类,则最后参与编译的分类优先执行类别的特点:
类别是在运行时决定的,在运运行时才会分配相应的内存空间,在就决定了在编译期是不能给某个类增加属性,否则会影响内存布局,从而导致crash ,若想给某个类增加一个属性,需要在运行时添加,首先先介绍下类别的结构:typedef struct category_t { const char *name; classref_t cls; struct method_list_t *instanceMethods; struct method_list_t *classMethods; struct protocol_list_t *protocols; struct property_list_t *instanceProperties; } category_t;
这个结构体理念包含这个类别的名字,实例方法,类方法,协议名,和实例属性
正如我们所知的那样,当我们重写类的一个方法以后,会覆盖原来类的方法,它为什么会覆盖原来类的方法呢,我们先来看一下当调用一个方法的时候是怎么运行的BOOL classExists = NO; if (cat->instanceMethods || cat->protocols || cat->instanceProperties) { addUnattachedCategoryForClass(cat, cls, hi); if (isRealized(cls)) { remethodizeClass(cls); classExists = YES; } if (PrintConnecting) { _objc_inform("CLASS: found category -%s(%s) %s", getName(cls), cat->name, classExists ? "on existing class" : ""); } } if (cat->classMethods || cat->protocols /* || cat->classProperties */) { addUnattachedCategoryForClass(cat, cls->isa, hi);//关联映射 if (isRealized(cls->isa)) { remethodizeClass(cls->isa);//添加事件 } if (PrintConnecting) { _objc_inform("CLASS: found category +%s(%s)", getName(cls), cat->name); } } 可以减少单个文件的体积可以把不同的功能组织到不同的Category里可以由多个开发者共同完成一个类,我们在开发时,会给自己写的一些分类直接拖入项目中。提高开发的效率。可以按需加载想要的category利用runtime给分类添加属性:
实际上,Category实际上允许添加属性的,同样可以使用@property,但是不会生成_变量(带下划线的成员变量),也不会生成添加属性的getter和setter方法,所以,尽管添加了属性,也无法使用点语法调用getter和setter方法。但实际上可以使用Runtime去实现Category为已有的类添加新的属性并生成getter和setter方法。//创建一个NSArray的Category,NSArray+MyCategory.h文件: // NSArray+MyCategory.h #import @interface NSArray (MyCategory) //不会生成添加属性的getter和setter方法,必须我们手动生成 @property (nonatomic, copy) NSString *blog; @end// NSArray+MyCategory.m文件:
// NSArray+MyCategory.m文件: #import "NSArray+MyCategory.h" #import @implementation NSArray (MyCategory) // 定义关联的key static const char *key = "blog"; /** blog的getter方法 */ - (NSString *)blog { // 根据关联的key,获取关联的值。 return objc_getAssociatedObject(self, key); } /** blog的setter方法 */ - (void)setBlog:(NSString *)blog { // 第一个参数:给哪个对象添加关联 // 第二个参数:关联的key,通过这个key获取 // 第三个参数:关联的value // 第四个参数:关联的策略 objc_setAssociatedObject(self, key, blog, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end// 测试代码 -(void)categoryTest{ NSArray *myArray = [[NSArray alloc]init]; myArray.blog = @"https://www.jianshu.com/p/e24bd3ee4ef4"; NSLog(@"Category添加属性。 用Category为NSArray添加了一个blog属性,blog=%@",myArray.blog); } ---------------------------------------------------- // 打印结果 ----> Category添加属性。 用Category为NSArray添加了一个blog属性,blog=https://www.jianshu.com/p/e24bd3ee4ef4
使用注意:分类只能增加方法,不能增加实例变量。(但是可以利用Runtime的关联对象)分类方法实现中可以访问原来类中声明的成员变量。分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用(实际上并没有真的替换,而是Category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的Category的方法会"覆盖"掉原来类的同名方法,这是因为运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会罢休,殊不知后面可能还有一样名字的方法)。当分类、原来类、原来类的父类中有相同方法时,方法调用的优先级:分类(最后参与编译的分类优先) –> 原来类 –> 父类,即先去调用分类中的方法,分类中没这个方法再去原来类中找,原来类中没有再去父类中找。如果多个category中存在同名的方法,运行时到底调用哪个方法由编译器决定,最后一个参与编译的方法会被调用。Category是在runtime时候加载,而不是在编译的时候。
Extension与Category区别Extension在编译器决议,是类的一部分,在编译器和头文件的@interface和实现文件里的@implement一起形成了一个完整的类。伴随着类的产生而产生,也随着类的消失而消失。Extension一般用来隐藏类的私有消息,你必须有一个类的源码才能添加一个类的Extension,所以对于系统一些类,如NSString,就无法添加类扩展Category是运行期决议的类扩展可以添加实例变量,分类不能添加实例变量(原因:因为在运行期,对象的内存布局已经确定,如果添加实例变量会破坏类的内部布局,这对编译性语言是灾难性的。
。
社群营销成功运营社群5要素之运营作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,
社群营销企业社群的3种变现模式作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,
社群营销你不得不知社群的5个核心特征作者小蚱蜢简介8年互联网营销实战经验,乐于为大家分享实战经验。寻找互联网营销同行交流经验提升自我。精力有限,不卖课程,不付费学习,单纯以互联网交流为主,所有文章纯属本人实战及见解,
拼多多这次惹祸了?只因平台推出这个功能你是否看到手机提示有人要添加好友,出于惯性就会点进去看。就在近日拼多多利用这个心理吸引用户,导致广大用户一致的反感。拼多多起家是靠裂变营销模式,通过用户拉亲朋好友一起拼单,从以低投
真正的高手,都掌握了反人性能力渡一教育世界上有两种东西不可直视,一种是太阳,另一种,便是人性。人性总是难以克制,我们总是习惯于用最轻易的方式寻找人生的捷径,但事实上,如果你肆无忌惮地放纵自己的人性,那么人性也会肆无忌惮
当雷军穿上鸿星尔克渡一教育最近,雷老师又开始了微博云晨练,一连七天晒出自己的跑步运动鞋第一天,雷老师穿上了为河南捐款5000万的安踏,第二天是同样捐款5000万的鸿星尔克,第三天是捐款2500万的李宁。之后
普通程序员和大神程序员,到底有啥区别?渡一教育众所周知,雷军本就是一位超级厉害的程序员。他曾经这样评价自己的编码水平我没写过诗,但是有人评价我写的代码像诗一样优雅。好吧,有被凡到。尽管很多人曾因为雷总过于浓密的发量而怀疑他作为
编程找不到灵感?试试这些游戏!渡一教育没有什么知识是在游戏中学不到的如果有那就多玩几款尼古拉斯亚里士多德赵四小时候,在东北流传着这样一个民间传说你要什么,你就像什么。妈妈我想要个书包。我看你像个书包。妈妈我想要个电脑。
闲鱼唐僧?渡一教育华为的老大任正非说过技术让人拥有更多主观能动性和权利。可是在当今这个技术高速发展的时代,相比于提升自己,年轻人却更多地想躺平,想法是很美好,但竞争无处不在,在无法心安理得的堕落的同
如何辨别伪大神程序员渡一教育成年人的世界里,没有王子和灰姑娘的童话,只有暗搓搓地分级比较,逐渐内卷,而在程序员的世界里,菜鸟程序员普通程序员大牛程序员大神程序员的内卷开始出现在了发量这个残酷而悲伤的现实之上。
程序员常犯的错误,过来人简直不要太真实渡一教育日常工作中的程序员们,其实都或多或少踩过一些编程的雷区,有时会不会犯这些错误,其实和你技术高低没有必然的联系,只是你有没有意识到这样做会造成不好的结果。今天小渡要分享给大家的,就是