一 、类别 (Category):
(一)适用场景:在不能查看类源文件的情况下向类中添加私有方法。
(二)使用方式:
1.创建:
(注意事项:类别名称必须唯一。)
2.声明:
@interface 原类名 (扩展的类别名).
@property (retain,nonatomic) 属性1;//属性必须是@dynamic类型。
@property (retain,nonatomic) 属性2;
/*类别的方法都有可实现与不可实现两种属性*/
@required;//必须实现的方法。
-(返回值)方法一;
@optional;//可选实现的方法。
-(返回值)方法二;
@end
(注意事项:类别中不可以添加实例变量,但是可以添加属性,只是属性必须是@dynamic类型。)
3.实现:
4.调用:当前类的任意对象都可以调用这些方法。
(三)注意细节:
1.类别可以访问其继承类的实例变量,而且类别方法的优先级要高于其继承类方法的优先级。
(四)优缺点:
缺点:
1.无法定义实例变量,因为类别只是给已有类添加方法,所以并不开辟空间。
2.类别方法名称要保证不能跟现有类中的方法重名,因为类别方法的优先级高于所属类方法的优先级,当两者重名的时候,原方法无效。
优点:
1.可以将类别的实现分散于多个不同的文件中或者框架中
2.创建对私有方法的前向引用。
3.以及向对象添加非正式协议。
二、延展 (Extension)
延展其实就是类别的一种特殊情况,对类别做的延伸。
(一)适用场景:适用于可以常看类源文件的情况,可以直接在源文件中添加方法和实例变量或属性。
(二)特点:
1.不需要起名字,直接在类的实现文件中添加。
2.可以添加实例变量。
3.可以修改当前类属性的特性。
例如:@property (readonly,assign) NSInteger thing;//原有类的属性
@property (readwrite,assign) NSInteger thing;//延展的属性,编译器会自动给这个属性添加setter方法。
(三)使用方式:
@interface 当前类名 ()
{
实例变量1;//这里的实例变量都是私有的(@private),并不是默认的受保护的(@protected)。所以,只能当前类访问。
实例变量2;
}
@property (readonly,assign) NSInteger thing1;
三、协议 (Protocol)
(一)适用场景:
(二)使用:
1.声明:
@protocol 协议名 <父类协议> /*协议名称也必须是唯一的*/
{
实例变量1;
实例变量2;
}
在类的声明中引入协议
@interface 类名 :父类 <协议1,协议2,..........>
方法一;
方法二;
@end
2.实现:需要遵守某个协议的类去实现协议中的方法。
(三)、协议和数据类型
可以为实例变量和函数参数中的数据类型指定需要遵循的协议。表示该类型的对象必须遵循某个协议。
例如:
@property (retain,monatomic) id<协议名>对象指针;
-(返回值类型)方法名:(参数类型<协议名>)形参;
注意:可以通过一个方法来判断代理是否实现了某个方法,可以使用“[self.delegate respondsToSelector:(SEL)]”这个方法返回值是BOOl类型,所以可以通过添加到if语句中来防止因为代理没有实现某个方法而崩溃。
使用delegate的步骤
第一步:先搞清楚谁是谁的代理
第二步:定义代理协议,协议名称的命名规范: 控件类名 + Delegate 。
第三步:定义代理方法
代理方法一般都是定义为@optional
代理方法名一般都是以控件名开头
代理方法至少有一个参数,将控件本身传过去
第四步:设置代理(delegate)对象 比如:myView.delegate = xxxx;
第五步:代理对象签署协议
第六步:代理对象实现协议中应该实现的方法。