iOS分类和类扩展的基本使用

一、Category

Category:分类(类别、类目), 是Objective-C 的语法,顾名思义就是将一个类分成多个模块

Objective-C Runtime源码

typedef struct objc_category *Category;

struct objc_category {
	char *category_name;                          //分类名
	char *class_name;                             //分类所属的类名
	struct objc_method_list *instance_methods;    //实例方法列表
 	struct objc_method_list *class_methods;       //类方法列表
 	struct objc_protocol_list *protocols;         //分类实现的协议
};

根据源码可以看出, 这个分类结构体主要是给原有类添加方法的,而且结构体里也没有属性列表,所有原则上讲它只能添加方法, 不能添加属性

分类的语法格式:

@interface 待分类的类名(分类的名称)
@end

@implementation 待分类的类名(分类的名称)
@end

分类的作用:

1.将臃肿的类分为多个模块,方便管理
2.扩展一个类,给原来的类添加方法,特别是扩展系统自带的类或一些第三方框架
其中为系统的类写的分类也叫非正式协议

注意:
1.分类只能增加方法,不能增加属性
2.分类中的可以写@property, 但不会生成setter/getter方法
3.分类中可以访问原来类中的成员变量,但是只能访问@protect和@public形式的变量。如果想要访问本类中的私有变量,分类和子类一样,只能通过方法来访问。
4.如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法。
5.如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定,编译器会执行最后一个参与编译的分类中的方法。
可以在 TARGETS->Build Phases ->Compile Sources 修改(注意执行顺序是从上到下的)


二、Extension

Extension(类扩展)是Category的一个特例
特殊之处:
a.类扩展没有名字
b.只有声明没有实现,和原有的共享一个实现

类扩展格语法格式:

@interface 特扩展的类 ()

@end
作用:为一个类添加额外的原来没有变量,方法和属性
一般的类扩展写到.m文件中

一般的私有属性写到.m文件中的类扩展中

三、分类和类扩展的区别

1. 分类有名字,类扩展没有名字,是一个匿名的分类
2. 每一个分类都有单独的声明和实现,而类扩展只有声明,没有实现
3. 分类中只能新增方法,而类扩展不仅可以增加方法(必须实现),还可以增加实例变量(属性),该实例变量默认是@private类型的(用范围只能在自身类,而不是子类或其他地方)

4. 类扩展中声明的方法没被实现,编译器会报警,但是分类中的方法没被实现编译器是不会有任何警告的。这是因为类扩展是在编译阶段被添加到类中,而分类是在运行时添加到类中


类扩展的问题

08-06

相信大家在开发软件的时候都会遇到如下类扩展的情况,如下:rn[code=Java]class abstract A rn protected String s;rn rn //getS and setS functionrnrn public abstract void doA();rnrnrnclass A1 extends Arnrn public void doA()rn //doA codern rn[/code]rn然后做实例化的延时rn[code=Java]class AObjrnrn public static A newInstance()rn return (A)Factory.newInstance("com.a.A1");rn rnrnrnrnclass Factoryrn public static Object newInstance(String className)rn return Class.forName(className).newInstance();rn rn[/code]rn而后随着需求变化,出现了在利用A1类的某一个地方需要增加一个参数,于是写了如下的类:rn[code=Java]class A2 extends Arnrn protected String s2;rn rn //getS2 and setS2 functionrnrn public void doA()rn //doA codern rn[/code]rn那么怎么用得上这个类呢,不用直接用AObj.newInstance()了,不说她返回的是A1,就算是返回A2也不能,rnrn因为A中没有getS2 and setS2 function!rnrnrn1、修改了class AObj,如下:rn[code=Java]class AObjrn rn private static HashMap cnHM =new HashMap();rnrn public static A newInstance(String optKey)rn initHashMap();rn return (A)Factory.newInstance(cnHM.get(optKey));rn rnrn private static void initHashMap()rn cnHM.put("1", "com.a.A1");rn cnHM.put("2", "com.a.A2");rn rn[/code]rn并且修改了需要需求变化的地方与所有用到A1的地方rnA2 a2 = (A2)AObj.newInstance("2");rnA a1 = AObj.newInstance("1"); //所有用到A1的地方都要修改rnrn天哪,这太难受了rnrn2、新增加一个class A2Objrn[code=Java]class A2Objrnrn public static A newInstance()rn return (A)Factory.newInstance("com.a.A2");rn rnrn[/code]rn那么只需要修改了需要需求变化的地方:A2 a2 = A2Obj.newInstance();rnrn......rn///////////////////////////////////////////////////////////////////rn如上所述,都是要修改需要变化的地方的客户端代码,无论是rnA2 a2 = (A2)AObj.newInstance("2");rn还是rnA2 a2 = A2Obj.newInstance();rnrn如果说不这样修改吧,那么修改abstract A,在其加上一个参数s???天哪,这也是很恐怖的啊。rnrn现在的问题就是,如果能不修改需要变化的地方的客户端代码的话,应该怎么做呢??rnrn大家在开发过程中有什么更好的解决办法呢?或者碰到或什么样的问题,然后又是怎么解决的呢??

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试