Category与Extension

Category

  • 概述:Category是OC2.0之后添加的语言特性,Category又叫类别,分类等,能够在不改变原来类的内容基础上,为类增加一些方法(当然还有大家都知道的,虽然不能以正常方式为类添加属性,但是我们可以通过runtime来动态绑定添加,后面会讲到),除此之外Category还有以下功能
  1. 将类的实现分开写在几个分类里面,这样做的好处是
  • 可以减少单个文件的体积
  • 可以把不用的功能组织在不同的Category里
  • 可以由多个开发者共同完成一个类
  • 可以按需加载想要的Category
  1. 声明私有的方法
  2. 模拟多继承
  • 使用
    既然我们说Category只能为类增加方法,而不能添加属性,那么我们就去创建一个分类文件去验证以下,看看具体是个什么样的情况。

我们创建了一个Student和他的分类Student+Category

@interface Student : NSObject
@property (nonatomic,copy) NSString *age;
@property (nonatomic,copy) NSString *name;
@end
//Student+Category.h
@interface Student (Category)
@property (nonatomic,copy) NSString *schoolName;
@end

我们运行一下,可以发现他编译成功了并且运行成功了,


image
image

放开断点发现崩溃了,看错误日志我们知道了没有setSchoolName方法。那么问题来了,既然我们可以在分类中添加属性,但在调用的时候却会奔溃,这是为什么,我们先来看看Category的源码

Category
Category 是表示一个指向分类的结构体的指针,其定义如下:
typedef struct objc_category *Category;
struct objc_category {
  char *category_name                          OBJC2_UNAVAILABLE; // 分类名
  char *class_name                             OBJC2_UNAVAILABLE; // 分类所属的类名
  struct objc_method_list *instance_methods    OBJC2_UNAVAILABLE; // 实例方法列表
  struct objc_method_list *class_methods       OBJC2_UNAVAILABLE; // 类方法列表
  struct objc_protocol_list *protocols         OBJC2_UNAVAILABLE; // 分类所实现的协议列表
}

我们看到了什么,我们有发现实例方法列表,类方法类表,协议列表,但是没有属性列表。我们知道在一个类中用 @property 声明属性,编译器会自动帮我们生成 _成员变量名 和setter,getter方法,但是在分类的指针结构体中,根本就要没有属性类表,所以也就不能生成 _成员变量名 和setter,getter方法,因此我们的程序可以编译和运行都成功了,但是一旦有调用这个属性就会奔溃。

解决方案

  • 由于OC是动态语言,方法真正的实现是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法
#import "Student+Category.h"
#import <objc/runtime.h>
static const char *schoolNameKey = "schoolNameKey";
@implementation Student (Category)
- (void)setSchoolName:(NSString *)schoolName{
    objc_setAssociatedObject(self, &schoolNameKey, schoolName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)schoolName{
    return objc_getAssociatedObject(self, &schoolNameKey);
}
@end
  • 总结
  1. 分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。所以< 原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性> ;
  2. 分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量(编译时会报警告);
  3. 可以在分类中访问原有类中.h中的属性;
  4. 如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法。所以同名方法调用的优先级为 分类 > 本类 > 父类。因此在开发中尽量不要覆盖原有类;
  5. 如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。

Extension

  • Extension 是Category的一个特例,类扩展与分类相比只少了分类的名称以及.m文件,他常用的形式不是创建一个单独的文件,而是在实现文件中添加私有的成员变量、属性和方法。比如我们平时在创建一个类的时候我们会在.m文件中添加私有的成员变量、属性和方法,当然我们也可以在.h文件中添加,所以说Extension在我们平时的开发中是最常用的
@interface Student ()
{
    NSString *_core;
}
@property (nonatomic,copy) NSString *teachName;
- (void)study;
@end
  • 总结
  1. Extension的作用是为一个类添加额外的私有成员变量,属性以及方法
  2. 一般的类扩展写到.m文件里

Category和Extension的区别

  1. Category原则中只能增加方法(能添加属性的原因只是通过runtime解决没有setter和getter方法)
  2. Extension不仅可以增加方法,还可以增加属性,只是属性默认的访问权限是 private
  3. Extension中声明的方法没有在.m文件中实现,编译器会报警,但是在Category中的方法没有实现的话编译器是不会有任何警告的。这是因为Extension是在编译阶段添加到类中,而Categor是在运行时添加到类中的
  4. Extension不能像类别那样拥有独立的实现部分,他所声明的方法只能在其对应的类中实现
  5. Extension定义在.m文件的方法是私有的,定义在.h文件的方法是公有的
  6. Extension一般用来隐藏类的私有消息,你必须有一个类的源码才能添加一个类的Extension,所以对于系统一些类,如NSString,就无法添加类扩展,如果只是简单的创建Extension文件是能够创建成功的,但是如果你在文件中添加属性或者方法,在程序中一旦使用了该属性或者方法程序就会崩溃,会报找不到相对应的方法错误信息。

参考资料来源

  1. http://blog.csdn.net/haishu_zheng/article/details/12873151
  2. http://www.imlifengfeng.com/blog/?p=397
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容