OC正式协议和非正式协议的区别

简介: 最近看了些关于objective-c的正式协议和非正式协议的内容,发现还是有些混乱,可能是因为还不熟悉OC,对正式协议和非正式协议的使用还不是很熟练,所以想整理一下 非正式协议,是使用类别category来实现,非正式协议是NSObject的一个类别,这样任何类的对象都可以作为委托对象来使用,它可以列出对象能够执行的所有方法,这样用来实现委托, 我们可以使用选择器来判断该非正式协议中是否有这个方法。

最近看了些关于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.     NSLog(@"I am in showInfo");  
  7. }  
  8.   
  9. //实现协议必须实现的  
  10. -(int)printValue:(int)value1 andValue:(int)value2  
  11. {  
  12.     NSLog(@"print value1 %d,value2 %d",value1,value2);  
  13.     return 0;  
  14. }  
  15.   
  16. //实现可选的  
  17. -(void)print:(int)value  
  18. {  
  19.     NSLog(@"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.     NSLog(@"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

  1. #import <Foundation/Foundation.h>  
  2. @protocol dogBark;  
  3.   
  4. @interface Dog : NSObject {  
  5.     int _ID;  
  6.     NSTimer *timer;  
  7.     int barkCount;  
  8.     id <dogBark> delegate;        //存放狗的主人  
  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.       NSLog(@"dog bar %d",barkCount);  
  21.       //调用主人delegate的bark:count方法,   
  22.       [delegate bark:self count:barkCount]; //回调机制  
  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.     NSLog(@"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.     NSLog(@"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.     NSLog(@"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.     NSLog(@"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.     NSLog(@"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方法


类别主要有三个功能:

一、利用类别分散实现

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

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

相关文章
|
iOS开发 Swift 缓存
iOS - UIViewController
前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UIViewController : UIResponder @available(iOS 2.0, *) public class UIViewController : UIResponder, NSCoding, UIAppearanceContainer, UITraitEnvironment, UIContentContainer, UIFocusEnvironment 视图控制器负责页面的创建、事件处理等。
1449 0
|
安全 Swift C语言
Swift和OC的区别
Swift和OC的区别
330 0
|
Android开发 容器 数据格式
安卓开发_深入理解Activity和Fragment的关系
Fragment(碎片)是必须嵌入在 Activity(活动) 中使用的。Fragment的生命周期随着Activity的生命周期的变化而变化 一、首先让我们看下Activity和Fragment的生命周期对比 二、通过代码来看一下 1 package com.
1140 0
|
iOS开发 开发者 前端开发
***iOS 项目的目录结构能看出你的开发经验
最近有师弟去面试iOS开发,他谈论到,面试官竟然问他怎么分目录结构的,而且还具体问到每个子目录的文件名。 目录结构确实很重要,面试官问他这些无疑是想窥探他的开发经验。清晰的目录结构,可让人一眼知道对应目录的职能,这也能体现开发者的经验和架构能力。
898 0
|
缓存 iOS开发
Xcode快捷键
Xcode快捷键
519 0
|
iOS开发 编译器 JavaScript
iOS八种内存泄漏问题
循环引用(Retain Cycle) 先简单说一下什么是循环引用(retain cycle) ​假设我们有两个实例A和B,B是A的一个strong型的property,则B的引用计数是1,当A的需要释放的时候,A则会调用[B release]来释放B,B的引用计数则减为0,释放。
2255 0
|
NoSQL iOS开发 C++
Xcode Debug 大全
BUG,简单来说就是程序运行结果与预期的不同,下面来说说Xcode中的DEBUG方法
452 0
|
自然语言处理 Java C#
block产生的内存泄漏以及解决方案(以及扩展)
block产生的内存泄漏以及解决方案(以及扩展)
538 0
|
机器学习/深度学习 数据采集 自然语言处理
PyTorch学习系列教程:构建一个深度学习模型需要哪几步?
继续PyTorch学习系列。前篇介绍了PyTorch中最为基础也最为核心的数据结构——Tensor,有了这些基本概念即可开始深度学习实践了。本篇围绕这一话题,本着提纲挈领删繁就简的原则,从宏观上介绍搭建深度学习模型的几个基本要素。
780 0
PyTorch学习系列教程:构建一个深度学习模型需要哪几步?
Python类三种方法,函数传参,类与实例变量(一)
1 Python的函数传递: 首先所有的变量都可以理解为内存中一个对象的‘引用’ a = 1 def func(a): a = 2 func(a) print(a) # 1 a = 1 def fun(a)...