1 摘要
本文通过一个简单的保姆看孩子的例子来体会代理设计模式的简单使用。
2 对代理的理解
下面的表述是在ARC开启的情况下。
1. 代理的原理
就是把代理的方法声明提取出来放在一个协议里面,谁包含(包含即可,而不一定非要遵守)该协议,即可正确写出(而不是调用)这些方法。
2. 代理的属性
因为是id类型,可以指向任何类型实例,只要该实例有这些方法的实现,则最后即可真正实现这些方法。其重点在于代理属性的类型id,所以可以将代理设为任何类型的实例,只要该实例所属的类有协议中方法的实现,既可通过该代理实例实现具体的方法。
3. 代理的本质
其实本质就是多态,id作为父类指针,可以执行任何类似的实例,只要该实例实现了协议中的方法,就可以调用该方法。表面上体现为父类指针,调用协议中的方法,其实是不同的实例来实现协议中的方法。
3 代理设计模式的作用
- A想让B做某事。
- A通知B发生了某事,或者给B传递参数。
- B需要监听A的行为
4 实例代码
4.1 Baby类代码
- .h文件
#import <Foundation/Foundation.h>
//#import "BabyDelegate.h"
//#import "Nanny.h"
// 仅仅是声明,并没有包含里面的方法。
@protocol BabyDelegate; // 协议的头文件可以暂时不包含,仅仅声明者是一个协议既可,但是.m文件中用到协议里面的方法,所以必须声明。
@interface Baby : NSObject
#pragma mark 重点1:此处的遵守协议代码无意义,去掉也可以运行。只要.m文件中直接或者间接包含有协议的声明就行。
@property(nonatomic)id <BabyDelegate>delegate;
@property(nonatomic)int age;
- (void)babyCry;
@end
- .m文件
#import "Baby.h"
#import "BabyDelegate.h" // 因为下面用到里面的方法,所以在这里该协议必须被间接或者直接的包含。
@implementation Baby
#pragma mark 重中之重:代理的作用:1.A想让B做某事。2.A通知B发生了某事,或者给B传递参数。3. B需要监听A的行为。
- (void)babyCry
{
NSLog(@"%d岁的baby哭了", _age);
[self.delegate comfortBaby:self];
}
@end
4.2 保姆类代码
- .h文件
#import <Foundation/Foundation.h>
//#import "BabyDelegate.h"
@protocol BabyDelegate;// 仅仅是声明。
#pragma mark 重点2:此处的遵守协议代码无意义,去掉也可以运行。只要.m文件中直接或者间接包含有协议的声明就行。
@interface Nanny : NSObject <BabyDelegate>
@end
- .m文件
#import "Nanny.h"
#import "Baby.h" // 因为用到其属性age,所以必须被包含,否则就可以用@class即可。
#import "BabyDelegate.h" // 因为下面用到协议里面的方法,所以此协议必须要直接或者间接的被包含。
@implementation Nanny
- (void)comfortBaby:(Baby *)baby
{
NSLog(@"%d岁的小孩不要哭了", baby.age);
}
@end
4.3 协议代码
#import <Foundation/Foundation.h>
#pragma mark 重点3:此处仅仅声明是一个类即可。
@class Baby;
@protocol BabyDelegate <NSObject>
- (void)comfortBaby:(Baby *)baby;
@end
4.4 main函数代码
//
// main.m
// 代理模式练习
//
// Created by dqw on 15/5/12.
// Copyright (c) 2015年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Baby.h"
#import "Nanny.h"
//#import "BabyDelegate.h"
#pragma mark 重点重点:1. 代理的原理,就是把代理的方法声明提取出来放在一个协议里面,谁包含(包含即可,而不一定非要遵守)该协议,即可正确写出(而不是调用)这些方法。
2. 代理的属性是id类型,可以指向任何类型实例,只要该实例有这些方法的实现,则最后即可真正实现这些方法。其重点在于代理属性的类型id,所以可以将代理设为任何类型的实例,只要该实例所属的类有协议中方法的实现,既可通过该代理实例实现具体的方法。
3. 3. 代理的本质就是多态,id作为父类指针,可以执行任何类似的实例,只要该实例实现了协议中的方法,就可以调用该方法。表面上体现为父类指针,调用协议中的方法,其实是不同的实例来实现协议中的方法。
int main(int argc, const char * argv[]) {
Baby *baby = [[Baby alloc]init];
baby.age = 2;
Nanny *nanny1 = [[Nanny alloc]init];
Nanny *nanny2 = [[Nanny alloc]init];
baby.delegate = nanny1;
///如果要实现这下面一行代码,则必须要在上面写#import "BabyDelegate.h",凡是出现方法的地方,必须要有声明。
// [baby.delegate comfortBaby:baby];
[baby babyCry];
return 0;
}
5 重点 难点 注意点
- 好像遵守协议只是各形式?
- ARC开启的情况下,在各种.m文件中,只要写到了方法名,则必须将其声明直接或间接包含
- 在ARC关闭的情况下,如果一个类只有方法的实现,则该类所对应的对象可以调用该方法。在ARC开启的情况下,在main函数中通过该类所对应的对象调用方法,代码编译不通过。而利用baby的代理属性通过类所属的对象间接可以调用方法??
- 一旦某个类遵守了协议(仅仅是遵守),则无论ARC是否开启,在类的m文件中不声明方法就直接定义协议中的方法是不可行的。从这里来看,遵守协议不不仅仅是个形式(优点多余的形式)。针对这种需要类实现方法的情况,遵守协议不仅仅是个形式,而对于baby类中,不需要类实现方法的情况,则遵守协议就仅仅是个形式。
6 疑问
- 遵守协议真的只是个形式吗?
- 开启ARC和不开启ARC为什么有这种区别,其本质是什么?
7 补充
- 上面的东西容易混,以后再多看看,搞清楚其本质,而不是仅仅记住这个现象。