在iOS中有很多种消息传递方式,这里先简单介绍一下各种消息传递方式。
-
通知:在iOS中由通知中心进行消息接收和消息广播,是一种一对多的消息传递方式。
-
代理:是一种通用的设计模式,iOS中对代理支持的很好,由代理对象、委托者、协议三部分组成。
-
block:iOS4.0中引入的一种回调方法,可以将回调处理代码直接写在block代码块中,看起来逻辑清晰代码整齐。
-
target action:通过将对象传递到另一个类中,在另一个类中将该对象当做target的方式,来调用该对象方法,从内存角度来说和代理类似。
-
KVO:NSObject的Category-NSKeyValueObserving,通过属性监听的方式来监测某个值的变化,当值发生变化时调用KVO的回调方法。
代理是一种通用的设计模式,在iOS中对代理设计模式支持的很好,有特定的语法来实现代理模式,OC语言可以通过@Protocol实现协议。
代理主要由三部分组成:
-
协议:用来指定代理双方可以做什么,必须做什么。
-
代理:根据指定的协议,完成委托方需要实现的功能。
-
委托:根据指定的协议,指定代理去完成什么功能。
协议有两个修饰符@optional和@required,创建一个协议如果没有声明,默认是@required状态的。这两个修饰符只是约定代理是否强制需要遵守协议,如果@required状态的方法代理没有遵守,会报一个黄色的警告,只是起一个约束的作用,没有其他功能。
无论是@optional还是@required,在委托方调用代理方法时都需要做一个判断,判断代理是否实现当前方法,否则会导致崩溃。
// 判断代理对象是否实现这个方法,没有实现会导致崩溃
if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) {
[self.delegate userLoginWithUsername:self.username.text password:self.password.text];
}
示例:假设我在公司正在敲代码,敲的正开心呢,突然口渴了,想喝一瓶红茶。这时我就可以拿起手机去外卖app上定一个红茶,然后外卖app就会下单给店铺并让店铺给我送过来。
这个过程中,外卖app就是我的代理,我就是委托方,我买了一瓶红茶并付给外卖app钱,这就是购买协议。我只需要从外卖app上购买就可以,具体的操作都由外卖app去处理,我只需要最后接收这瓶红茶就可以。我付的钱就是参数,最后送过来的红茶就是处理结果。
但是我买红茶的同时,我还想吃一份必胜客披萨,我需要另外向必胜客app去订餐,上面的外卖app并没有这个功能。我又向必胜客购买了一份披萨,必胜客当做我的代理去为我做这份披萨,并最后送到我手里。这就是多个代理对象,我就是委托方。
在iOS中一个代理可以有多个委托方,而一个委托方也可以有多个代理。我指定了外卖app和必胜客两个代理,也可以再指定麦当劳等多个代理,委托方也可以为多个代理服务。
代理对象在很多情况下其实是可以复用的,可以创建多个代理对象为多个委托方服务,在下面将会通过一个小例子介绍一下控制器代理的复用。
下面是一个简单的代理:
首先定义一个协议类,来定义公共协议
#import @protocol LoginProtocol @optional - (void)userLoginWithUsername:(NSString *)username password:(NSString *)password; @end 定义委托类,这里简单实现了一个用户登录功能,将用户登录后的账号密码传递出去,有代理来处理具体登录细节。 #import #import "LoginProtocol.h" /** * 当前类是委托类。用户登录后,让代理对象去实现登录的具体细节,委托类不需要知道其中实现的具体细节。 */ @interface LoginViewController : UIViewController // 通过属性来设置代理对象 @property (nonatomic, weak) id delegate; @end 实现部分: @implementation LoginViewController - (void)loginButtonClick:(UIButton *)button { // 判断代理对象是否实现这个方法,没有实现会导致崩溃 if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) { // 调用代理对象的登录方法,代理对象去实现登录方法 [self.delegate userLoginWithUsername:self.username.text password:self.password.text]; } } 代理方,实现具体的登录流程,委托方不需要知道实现细节。 // 遵守登录协议 @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; LoginViewController *loginVC = [[LoginViewController alloc] init]; loginVC.delegate = self; [self.navigationController pushViewController:loginVC animated:YES]; } /** * 代理方实现具体登录细节 */ - (void)userLoginWithUsername:(NSString *)username password:(NSString *)password { NSLog(@"username : %@, password : %@", username, password); }