代理和协议区别及应用

摘要:
符合协议的类将实现协议中指定的几个方法。很难用名词来定义(例如,我们可以说protocol实际上是一个方法列表)。您可以使用@required和@optional来配置必须实现的方法和可选方法以符合此协议。必须在协议中实现-returnChooseDay:还必须在MyChooseDayViewDelegate中实现方法(@required)以使用分类,然后引入所需的协议;
协议与代理

一、理解协议与代理

协议:

协议是一个方法签名的列表,在其中可以定义若干个方法。根据配置,遵守该协议的类会去实现这个协议中规定的若干个方法。

代理:

代理是一个概念,很难用一个名词去定义(如我们可以说协议其实就是一个方法列表)。它更像是一种关系,我要做某一个事情,但我自己不想去做这件事,我委托其他人帮我去做这件事。这个时候,这位其他人就是我的代理。



二、协议的使用

在定义协议时,可以通过@required与@optional来配置遵守这个协议必须去实现的方法和可以选择的方法。譬如:


@protocol MyChooseDayViewDelegate<NSObject>  
@required  
- returnChooseDay:(id)myChooseDayView;  
@optional  
- hideThisView;  
- changeDateFormatter:(NSString*)formatString;  
@end  
在定义的协议 MyChooseDayViewDelegate中,如果遵守该协议,就必须实现协议中的- returnChooseDay: 方法,同时可以根据实际程序要求去实现- hideThisView 与 - changeDateFormatter: 。

同时,协议支持对本身的一种扩展,譬如:


@protocol MyChooseTimeViewDelegate< MyChooseDayViewDelegate>  
- doSomething; 
@end  
MyChooseTimeViewDelegate扩展了MyChooseDayViewDelegate这个协议,也就是说,假如遵守了MyChooseTimeViewDelegate的话,也必须实现MyChooseDayViewDelegate中的方法(@required)使用分类的话,就是在定义类的头文件中使用<> 将所需要的协议引入,如果引入多个协议,用","分隔,譬如:

@interface MyClassView:UIViewController <MyChooseDayViewDelegate, UIAlertViewDelegate>  
//TODO: balabalabala...  
@end  

想要检查某个类是否实现了某个协议或者某个类是否实现了某个协议的方法,可以通过以下方式来进行测试

//获取某个对象  
MyClassView *myClassView = xxxxxxx;  
//判断该对象是否实现了MyChooseDayViewDelegate协议  
if([myClassView conformToProtocol:@protocol (MyChooseDayViewDelegate)]){  
//TODO: balabalabala...  
}  
//判断对象是否实现了某个方法就用我们经常会使用到的  
if([myClassView responseToSelector:@selector(xxxx)]){  
//TODO: balabalabala...  
}  

三、代理
代理在iOS开发会被经常使用,而且代理的使用往往配合着协议。我重复一次我对他的理解,我要做某一个事情,但我自己不想去做这件事,我委托其他人帮我去做这件事。
举例来说,我在办公室里正在写代码,突然发现口很渴像喝瓶冰百事,但下楼是件麻烦的事情,我不愿意下楼。这个时候我想起小卖部可以商品加价2元就外送到家服务,我就打电话给小卖部,委托小卖部给我送一瓶水上来。这个时候,小卖部就是我的代理,我委托他帮买水并送上来。这个例子中小卖部是我的代理,商品加价2元外送到家服务就是商品买卖协议(这个叫法肯定不是最佳的,姑且这么叫吧)中的一个方法。
不要觉得麻烦,我们再最后理一遍,小卖部遵守商品买卖协议,我让小卖部成为了我的代理,代替我完成了买瓶冰百事的事情。
以iOS开发的角度来说,UIViewController想使用一个tableview,需要遵守UITableviewDataSource,UITableViewDelegate这2个协议,同时设置tableview的代理为自身,才可以完整的实现Table。


四、代理与协议的使用
我尽可能的用代码来进行描述,但首先需要进行一些context铺垫
我想实现的功能:我要自定义一个View,这个view可能展示了我自己项目中特定的一些信息,它可能是若干控件的组合,譬如UITextField、UISwitch、UIDatePicker、balabalabala...我们姑且叫这个view为myInformationView  我在一个ViewController使用了这个view,为了方便,这个ViewController就叫myRootViewController。在使用这个myInformationView时,我需要即时的在myRootViewController获取并做相应的处理。这是我想实现的功能。
接下来,就是开始写代码的时刻:
1.首先是一个protocol

#import <Foundation/Foundation.h>  
@class MyInformationView;  
  
@protocol MyInformatioViewDelegate<NSObject>  
@required  
@returnValueToShow:(MyInformationView*)myInformationView;  
  
@end  

2.MyInformationView

#import <UIKit/UIKit.h>  
  
@interface MyInformationView : UIView  
  
@property (nonatomic, strong) id<MyInformationViewDelegate> myDelegate;  
  
  
- (id)initWith......//初始化视图的方法  
//所需要的属性和方法根据实际需要再行添加  
@end  
#import "MyInformationView.h"  
@interface MyInformationView()  
  
@end  


@implementation MyInformationView  
@synthesize myDelegate = _myDelegate;  
  
//Todo: 处理一些初始化方法和其他一些事件  
  
// changeMyInformationData 是操作此view可能产生的数据变动。它可能是选择器变动、点击按钮等等,但我们并不想在此view处理它,因为它的变动可能对调用此view的controller造成影响,所以...  
- (void) changeMyInformationData:(id)sender  
{  
    //TODO:数据变动....  
    if ([self.myDelegate respondsToSelector:@selector(returnValueToShow:)]) {  
            [self.myDelegate returnValueToShow:self];  
        }  
}  
  
@end  

3.ViewController
这里就不写代码了,在头文件中声明此类遵守MyInformationViewDelegate协议。在实现文件(.m)中,调用MyinfomationView的时候,设置代理成自己,
MyInformation *myInfoView = [[MyInformation alloc] init.......];
myInfoView.myDelegate = self;
然后实现协议中要求实现的方法

- (void)returnValueToShow:(MyInformationView*)myInfoView  
{  
   //TODO:做想做的事情  
}  

这样就是一整套完整的代理与协议组合用法了。但其实代理与协议还可以做更多的事情,例如在页面切换时(A页面进入AA页面)...通过传入,使AA成A的代理,并对其进行操作来方便处理一些问题。以后找机会会陆续介绍。这篇文章就写到这里,谢谢。

免责声明:文章转载自《代理和协议区别及应用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇css修改下拉列表select的默认样式使用canvas实现对图片的批量打码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ActivityManager

android.app.ActivityManager 这个类主要用来管理全部设备上的Activities。 权限:android.permission.GET_TASKS 方法:| 返回类型     方法| 1.List<ActivityManager.RecentTaskInfo>       getRecentTasks(int max...

H5_0009:关于HTML5中Canvas的宽、高设置问题

关于HTML5中Canvas的宽、高设置问题 Canvas元素默认宽 300px, 高 150px, 设置其宽高可以使用如下方法(不会被拉伸): 方法一:        <canvas  height="500"></canvas> 方法二:使用HTML5 Canvas API操作 OK        var canvas...

iOS进阶之多线程

多线程 注意:iOS关于UI的刷新和添加必须在主线程中操作! pthread的创建方法: pthread_t pthread; //第一个参数 线程指针 //第二个参数 线程的一些属性 //第三个参数 函数指针 用于执行方法 //第四个参数 线程中的传值 pthread_create(&pt...

ansible-任务控制tags

1. ansible-任务控制tags介绍        如果你有一个大型的剧本,那么只能运行它的特定部分而不是在剧本中运行所有内容可能会很有用。因此,Ansible支持“tags:”属性。        执行playbook时,可以通过两种方式根据 “tags” 过滤任务 在命令行上,使用或选项“--tags或 --skip-tags ” 在ansi...

UniAPP IAP支付流程

1,plus.payment.getChannels(function(channels) {}) //获取所有支付方式 2,let iap = channels.find(x => x.id == 'appleiap');  //筛选ios内购 iap 3,iap.requestOrder([内购商品ID], function(event) {}...

线程同步以及AutoResetEvent

近期在重构老项目时发现有些地方用了AutoResetEvent,于是查了些资料学习整理。 线程同步介绍 即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。 同步就是协同步调,按预定的先后次序进行运行。如...