分类(Category)
(1)、分类的基础知识
分类是在不改变原有类内容的基础上,为类增加一些方法的方式。
(2)、分类的注意事项
1>分类只能增加方法,不能增加成员变量;
2>在分类方法的实现中可以访问原来类中的成员变量;
3>分类中可以重新实现原来类中的方法,但是这样会导致原来的方法无法在使用
4>在大规模应用中。通常把相应的功能写成分类,对原有的类进行扩充,一般分模块写,一个模块一个分类
分类的实现
我们可以再上一节Student类的基础上增加分类:
CateStudent.h方法声明:
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 @interface Student (CatStudent) 4 - (void)eat; 5 - (void)study; 6 @end
CateStudent.m方法实现:
1 #import "CateStudent.h" 2 @implementation Student (CatStudent) 3 4 - (void)eat { 5 NSLog(@"add eat,age=%i...",age); 6 } 7 8 - (void)study { 9 NSLog(@"add study..."); 10 } 11 12 @end
main.m的实现:
1 #import <Foundation/Foundation.h> 2 #import "CateStudent.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]init]; 10 [stu eat]; 11 [stu study]; 12 [stu release]; 13 } 14 return 0; 15 }
协议(Protocol)
(1)、协议介绍
在ObjC中使用@protocol定义一组方法规范,实现此协议的类必须实现对应的方法。这就像面向对象编程语言中的接口一样,因为OC中Interface已经用于定义类了,所以定义接口用了一个新的关键字Protocol。
(2)、协议的注意事项
1>一个协议可以扩展自另一个协议,如果需要扩展多个协议中间使用逗号分隔;
2>和其他高级语言中接口不同的是协议中定义的方法不一定是必须实现的,我们可以通过关键字进行@required和@optional进行设置,如果不设置则默认是@required(注意ObjC是弱语法,即使不实现必选方法编译运行也不会报错);
3>协议通过<>进行实现,一个类可以同时实现多个协议,中间通过逗号分隔;
4>协议的实现只能在类的声明上,不能放到类的实现上(也就是说必须写成@interface Person:NSObject<AnimalDelegate>而不能写成@implementation Person<AnimalDelegate>);
5>协议中不能定义属性、成员变量等,只能定义方法;
三、协议的实现
协议的声明PersonDelegate.h文件:
1 #import <Foundation/Foundation.h> 2 3 @protocol PersonDelegate <NSObject> 4 @required 5 - (void) eat; 6 7 @optional 8 9 - (void)run; 10 - (void)say; 11 @end
Student.h文件:
1 #import <Foundation/Foundation.h> 2 #import "PersonDelegate.h" 3 @interface Student : NSObject<PersonDelegate> 4 5 - (void) eat; 6 - (void) study; 7 8 @end
Student.m文件:
1 #import "Student.h" 2 3 @implementation Student 4 - (void) eat { 5 NSLog(@"eat..."); 6 } 7 - (void) study { 8 NSLog(@"study..."); 9 } 10 @end
代码块(Block)
在很多语言中的事件机制都是通过回调函数来实现的,因为框架不能提前知道在发生某个事件的时候用户如何处理这个事件,所以在框架要提供一个能让用户注册自己的事件处理函数的功能。在ObjC中也有类似的方法,称之为代码块(Block)。Block就是一个函数体(匿名函数),它是OC对于闭包的实现,在块状中我们可以持有或引用局部变量,同时利用Block也可以将一个函数作为一个参数进行传递。
MyButton.h
1 #import <Foundation/Foundation.h> 2 @class MyButton; 3 typedef void(^clickEvent)(MyButton*); 4 5 @interface MyButton : NSObject 6 7 @property(nonatomic,copy)clickEvent click; 8 -(void)onClick; 9 @end
MyButton.m
1 #import "MyButton.h" 2 3 @implementation MyButton 4 5 -(void)onClick{ 6 NSLog(@"on click it..."); 7 if(self.click){ 8 _click(self); 9 } 10 } 11 @end
main.m
1 #import <Foundation/Foundation.h> 2 #import "MyButton.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 MyButton *btn=[[MyButton alloc]init]; 8 btn.click=^(MyButton *b){ 9 NSLog(@"this is click event..."); 10 }; 11 [btn onClick]; 12 } 13 return 0; 14 }
关于Block需要注意一下几点:
- Block类型定义:返回值类型(^ 变量名)(参数列表)
- Block的实现:^(参数列表){操作主体};
- Block中可以读取块外面定义的变量但是不能修改,如果要修改那么这个变量必须声明_block修饰;