最近看了些关于objective-c的正式协议和非正式协议的内容,发现还是有些混乱,可能是因为还不熟悉OC,对正式协议和非正式协议的使用还不是很熟练,所以想整理一下
非正式协议,是使用类别category来实现,非正式协议是NSObject的一个类别,这样任何类的对象都可以作为委托对象来使用,它可以列出对象能够执行的所有方法,这样用来实现委托, 我们可以使用选择器来判断该非正式协议中是否有这个方法。
正式协议,是一个命名的方法列表,与非正式协议相比不同的是,它要求显示的采用协议,采用协议的方法是在类的@interface声明中列出协议的名称,此时,实现协议的类应该遵守协议,承诺实现协议中的所有方法,否则编译器将会发出警告。
协议类似于C++的纯虚函数,协议只有声明,没有实现,用来在子类中实现,协议中的方法有两类属性,@required和@optional两种,@required属性的要求实现协议的类必须要实现这种方法,而@optional属性的方法则不要求,如果不确定协议是否被实现,可以使用respondsToSelector:@select()来判断。
下面是一个协议的声明和实现实例代码:
声明一个协议myprotocol
1. @protocol myprotocol <NSObject>
2. @optional
3. -(void)print:(int)value;
4. //可选的方法
5.
6. @required
7. -(int)printValue:(int)value1 andValue:(int)value2;
8. //必须实现的
9.
10. @end
实现这个协议
mytest.h
1. #import <Foundation/Foundation.h>
2. #import "myprotocol.h"
3.
4. //实现协议 myprotocol
5. @interface mytest : NSObject<myprotocol>
6. {
7.
8. }
9. - (void)showInfo;
10. @end
mytest.m
1. #import "mytest.h"
2.
3. @implementation mytest
4. -(void)showInfo
5. {
6. "I am in showInfo");
7. }
8.
9. //实现协议必须实现的
10. -(int)printValue:(int)value1 andValue:(int)value2
11. {
12. "print value1 %d,value2 %d",value1,value2);
13. return 0;
14. }
15.
16. //实现可选的
17. -(void)print:(int)value
18. {
19. "print value is %d",value);
20. }
21.
22. @end
使用这个协议main.m
1. #import "mytest.h"
2. #import "myprotocol.h"
3.
4. int main (int argc, const char * argv[]) {
5. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
6.
7. // insert code here...
8. "Hello, World!");
9.
10. mytest *test=[[mytest alloc]init];
11. [test showInfo];
12. [test printValue:20 andValue:30];
13. //print协议是可选的,所以在用之前一定要判断是否实现了,不然可能会出错,使用下面的方法
14. // [test print:20];
15. SEL sel=@selector(print:);
16. if([test respondsToSelector:sel]){
17. [test print:11];
18. }
19.
20. //用协议的方式实现
21. id<myprotocol> protocol =[[[mytest alloc]init]autorelease];
22. [protocol showInfo];
23. [protocol printValue:200 andValue:300];
24. if([protocol respondsToSelector:@selector(print:)]){
25. [protocol print:111];
26. }
27.
28. [test release];
29. [pool drain];
30. return 0;
31. }
下面介绍使用正式协议来实现代理,或者叫委托,委托是一中推向,另一个类的对象会要求委托对象来执行它的某些操作。
下面的例子,有一个dog类,一个person类,每个person对象有一个狗,这条狗仅仅属于这个主人,狗会定时的通知主人,也就是调用person类的一些方法,这样在狗的类中就需要一个person的代理,要求主人调用一些方法,机制类似回调,如下:
dog.h
1. #import <Foundation/Foundation.h>
2. @protocol dogBark;
3.
4. @interface Dog : NSObject {
5. int _ID;
6. NSTimer *timer;
7. int barkCount;
8. //存放狗的主人
9.
10. }
11. @property int ID;
12. @property (assign)id <dogBark> delegate;
13.
14. @end
15.
16. //定义一个人和狗通讯的协议 protocol
17. @protocol dogBark<NSObject>
18. -(void)bark:(Dog*)thisDog count:(int)count;
19.
20. @end
dog.m
1. #import "Dog.h"
2.
3.
4. @implementation Dog
5. @synthesize ID=_ID;
6. @synthesize delegate;
7. -(id)init
8. {
9. if(self = [super init]){
10. //创建一个定时器user,每隔1.0s 就调用updateTimer:nil,并传递一个参数nil
11. timer=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];
12.
13. }
14. return self;
15. }
16.
17. -(void) updateTimer:(id)arg
18. {
19. barkCount++;
20. "dog bar %d",barkCount);
21. //调用主人delegate的bark:count方法,
22. //回调机制
23. }
24.
25. @end
person.h
1. #import <Foundation/Foundation.h>
2. #import "Dog.h"
3.
4. @interface Person : NSObject<dogBark>
5. {
6.
7. Dog *_dog;
8. }
9.
10. @property (retain) Dog *dog;
11. @end
person.m
1. #import "Person.h"
2.
3. @implementation Person
4. @synthesize dog=_dog;
5. -(void)setDog:(Dog*)aDog
6. {
7. if(_dog!=aDog){
8. [_dog release];
9. _dog=[aDog retain];
10. // 通知dog的主人是当前人,self
11. [_dog setDelegate:self];
12.
13. }
14. }
15.
16. //当狗叫的时候,让狗来调用人的方法
17. //这个方法来源于dogBark协议,Person类来实现
18. -(void)bark:(Dog*)thisDog count:(int)count
19. {
20. "Person bark: this dog %d bark %d",[thisDog ID],count);
21. }
22.
23. -(void)dealloc
24. {
25. self.dog=nil;
26. [super dealloc];
27. }
28.
29. @end
主函数mian.m
1. #import <Foundation/Foundation.h>
2. #import "Dog.h"
3. #import "Person.h"
4.
5.
6. int main (int argc, const char * argv[]) {
7. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
8.
9. // insert code here...
10. "Hello, World!");
11. Person *xiaoli = [[Person alloc]init];
12. Dog *dog=[[Dog alloc]init];
13. [dog setID:10];
14. [xiaoli setDog:dog];
15. [dog release];
16. //程序循环在这里
17. while (1) {
18. [[NSRunLoop currentRunLoop]run];
19. }
20. [xiaoli release];
21.
22. [pool drain];
23. return 0;
24. }
使用非正式协议也可以实现委托,前面讲非正式协议是使用类别来实现的,
同样的是一个dog类,一个person类,person类有一条狗,再实现一个NSObject的类别,在类别中实现一个方法,通过dog对象来调用这个方法。
1. #import <Cocoa/Cocoa.h>
2.
3. @interface dog : NSObject {
4. int _ID;
5. }
6. @property int ID;
7.
8. @end
1. #import "dog.h"
2.
3. @implementation dog
4. @synthesize ID=_ID;
5. -(id)init
6. {
7. self=[super init];
8. return self;
9. }
10.
11. @end
person类
1. #import <Cocoa/Cocoa.h>
2. #import "dog.h"
3.
4. @interface person : NSObject
5. {
6. dog *_mydog;
7. }
8.
9. -(void)setDog:(dog*)aDog;
10. -(id)mydog;
11. -(void)callFun;
12. @end
1. #import "person.h"
2. #import "nsobject_categroy.h"
3.
4. @implementation person
5.
6. -(void)setDog:(dog*)aDog
7. {
8. if (_mydog!=aDog) {
9. [_mydog release];
10. _mydog=[aDog retain];
11. }
12. }
13.
14. -(id)mydog{
15. return _mydog;
16. }
17.
18. -(void)callFun{
19. "call Fun!");
20. [_mydog callFromNSObject];
21. }
22.
23. -(void)dealloc{
24. [self setDog:nil];
25. [super dealloc];
26. }
27. @end
NSObject类别的实现,也就是非正式协议
1. #import <Cocoa/Cocoa.h>
2.
3.
4. @interface NSObject(myCategroy)
5. -(void)callFromNSObject;
6. @end
1. #import "nsobject_categroy.h"
2.
3.
4. @implementation NSObject(myCategroy)
5. -(void)callFromNSObject
6. {
7. "I AM NSOBJECT FUNCTIONS");
8. }
9. @end
主函数:
1. #import <Foundation/Foundation.h>
2. #import "person.h"
3. #import "dog.h"
4.
5. int main (int argc, const char * argv[]) {
6. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
7.
8. // insert code here...
9. "Hello, World!");
10. dog *d=[[dog alloc]init];
11. [d setID:10];
12. person *p=[[person alloc]init];
13. [p setDog:d];
14. [p callFun];
15. [p release];
16. [pool drain];
17. return 0;
18. }
这样就会调用callFromNSObject方法
类别主要有三个功能:
一、利用类别分散实现
二、利用类别创建前向引用,可以实现私有函数
三、非正式协议和委托类别