委托(delegate)也叫代理是iOS开发中常用的设计模式。我们借助于protocol可以很方便的实现这种设计模式。
什么是代理?
苹果的官方文档给了很清晰的解释:
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.
意译一下就是:代理是一种简单而功能强大的设计模式,这种模式用于一个对象“代表”另外一个对象和程序中其他的对象进行交互。 主对象(这里指的是delegating object)中维护一个代理(delegate)的引用并且在合适的时候向这个代理发送消息。这个消息通知“代理”主对象即将处理或是已经处理完了某一个事件。这个代理可以通过更新自己或是其它对象的UI界面或是其它状态来响应主对象所发送过来的这个事件的消息。或是在某些情况下能返回一个值来影响其它即将发生的事件该如何来处理。代理的主要价值是它可以让你容易的定制各种对象的行为。注意这里的代理是个名词,它本身是一个对象,这个对象是专门代表被代理对象来和程序中其他对象打交道的。
Cocoa中的代理
Cocoa Touch框架里大量使用了代理这种设计模式,在每个UI控件类里面都声明了一个类型为id的delegate或是dataSource,查看Cocoa的头文件可以发现很多如下的属性:
@property(nonatomic, assign)id < UIActionSheetDelegate > delegate; // weak reference
通常格式为@property(nonatomic, assign)id delegate; 即这个代理要遵循某一个协议,也就是说只有遵循了这个协议的类对象才具备代理资格。这同时也要求了代理类必须在头文件中声明遵循这个protocol_name协议并实现其中的@required方法,@optional的方法是可选的。
怎样写一个代理设计模式
- 你要明确你的协议名称,一般来讲名称都是:控件类名 + Delegate
- 代理方法中一般都是声明为@optional(程序默认情况下是@required)
- 代理方法名一般以控件开头
- 代理方法至少有一个参数
首先,我们创建一个婴儿类,继承自NSObject ,接下来在.h文件中创建下面的代码
#import <Foundation/Foundation.h>
@class Baby;
// 定义一份代理协议
@protocol BabyDelegate <NSObject>
- (void)babyWantEat:(Baby *)baby;
- (void)babyWantSleep:(Baby *)baby;
@end
@interface Baby : NSObject
/** 吃了多少东西 */
@property (nonatomic, assign) int food;
/** 睡意 */
@property (nonatomic, assign) int sleep;
/** 饿了 */
- (void)wantEat;
/** 困了 */
- (void)wantSleep;
/** 代理对象 */
@property (nonatomic, strong) id<BabyDelegate> delegate;
@end
接下来是.m文件中创建下面的文件
#import "Baby.h"
@implementation Baby
- (void)wantEat
{
NSLog(@"婴儿想吃东西");
// 通知保姆喂婴儿
[self.delegate babyWantEat:self];
}
- (void)wantSleep
{
NSLog(@"婴儿想睡觉");
// 通知保姆哄婴儿睡觉
[self.delegate babyWantSleep:self];
}
@end
下面创建一个保姆类同样继承自NSObject,下面是.h文件中的代码
#import <Foundation/Foundation.h>
@protocol BabyDelegate;
@interface Nurse : NSObject <BabyDelegate>
@end
接下来是.m文件中保姆需要在什么时候做什么事情,这个还是很有必要的,
#import "Nurse.h"
#import "Baby.h"
@implementation Nurse
- (void)babyWantEat:(Baby *)baby
{
baby.food += 20;
NSLog(@"Nurse喂婴儿吃东西--现在的食量是%d", baby.food);
}
- (void)babyWantSleep:(Baby *)baby
{
baby.sleep += 20;
NSLog(@"Nurse哄婴儿睡觉--现在的睡意是%d", baby.sleep);
}
@end
为什么会有delegate模式
换句话说,它可以用来解决神马问题?
当一个类的某些功能需要被别人来实现,但是既不明确是些什么功能,又不明确谁来实现这些功能的时候,委托模式就可以派上用场。
例如你可以再写个C类,实现-(void)transparendValue:(NSString*)fromValue {NSLog(@”%@ ,我是C”,value); }也是完全可以的。换谁来,只要它实现了这个方法,我就可以委托它来做这个事。
说到底一切都是为了使类之间的耦合性更松散。好的代码应该对扩展开放,对修改关闭。