最近看了些关于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 <Foundation/Foundation.h>  
2. #import "mytest.h"  
3. #import "myprotocol.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.       
11.     mytest *test=[[mytest alloc]init];  
12.     [test showInfo];  
13.     [test printValue:20 andValue:30];  
14. //print协议是可选的,所以在用之前一定要判断是否实现了,不然可能会出错,使用下面的方法  
15. //  [test print:20];  
16.     SEL sel=@selector(print:);  
17. if([test respondsToSelector:sel]){  
18.         [test print:11];  
19.     }  
20.       
21. //用协议的方式实现  
22.     id<myprotocol> protocol =[[[mytest alloc]init]autorelease];  
23.     [protocol showInfo];  
24.     [protocol printValue:200 andValue:300];  
25. if([protocol respondsToSelector:@selector(print:)]){  
26.         [protocol print:111];  
27.     }  
28.   
29.     [test release];  
30.     [pool drain];  
31. return 0;  
32. }

下面介绍使用正式协议来实现代理,或者叫委托,委托是一中推向,另一个类的对象会要求委托对象来执行它的某些操作。

下面的例子,有一个dog类,一个person类,每个person对象有一个狗,这条狗仅仅属于这个主人,狗会定时的通知主人,也就是调用person类的一些方法,这样在狗的类中就需要一个person的代理,要求主人调用一些方法,机制类似回调,如下:

dog.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 "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方法

类别主要有三个功能:

一、利用类别分散实现

二、利用类别创建前向引用,可以实现私有函数

三、非正式协议和委托类别