代理(delegate)设计模式

来源:互联网 发布:卖家开通淘宝客条件 编辑:程序博客网 时间:2024/05/22 01:54

代理设计模式

知识点掌握

  • 什么是设计模式
  • 代理设计模式的作用
  • 掌握 iOS 开发中,代理设计模式的工作原理和代码实现

什么是设计模式

  • 设计模式的产生是在无数份代码的经验累积下产生的
  • 每一个设计模式用于解决一种问题
  • 在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案
  • 设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案
  • 面向对象设计模式通常以类或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类或对象

代理设计模式

  • 代理设计模式的核心就是“解耦”

代理设计模式的代码实现

目标

  • 伪代码的方式体验代理设计模式的工作原理和 iOS 中代理设计模式的编写方法
  • 模拟目标:缩放视图

准备工作

  • 新建项目
  • 新建视图 CZScrollView 继承自 UIView 模拟滚动视图
/// 模拟 ScrollView@interface CZScrollView : UIView@end
  • CZScrollView 实现以下代码,当用户创建视图时,调用 setupUI 方法设置界面
@implementation CZScrollView- (instancetype)initWithFrame:(CGRect)frame {    self = [super initWithFrame:frame];    if (self) {        [self setupUI];    }    return self;}#pragma mark - 设置界面- (void)setupUI {}@end
  • ViewController 中导入头文件
#import "CZScrollView.h"
  • 实现以下代码添加滚动视图
@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    [self setupUI];}#pragma mark - 设置界面- (void)setupUI {    CZScrollView *sv = [[CZScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];    sv.center = self.view.center;    sv.backgroundColor = [UIColor lightGrayColor];    [self.view addSubview:sv];}@end

模拟系统交互缩放视图

要求,增加一个按钮,点击按钮缩放视图

CZScrollViewsetupUI 方法中添加以下代码

// 1. 添加按钮UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];btn.center = self.center;[self addSubview:btn];
  • 定义监听方法
#pragma mark - 监听方法- (void)缩放给定的视图 {}
  • setupUI 方法中给按钮添加监听方法
// 2. 添加监听方法[btn addTarget:self action:@selector(缩放给定的视图) forControlEvents:UIControlEventTouchUpInside];
  • 准备实现监听方法,模拟缩放视图

问题来了

不知道要缩放谁?

代理设计模式闪亮登场!

第一步 —— 协议 & 代理
  • CZScrollView 中定义代理属性
/// 我的代理,负责告诉我我来缩放谁@property (nonatomic, weak) id delegate;

滚动视图对代理的要求

  • 负责告诉我缩放谁
  • 滚动视图不关心代理的类型 —— id,只要你告诉我,我就给你干活

提示:weak 属性单独讲

矛盾点出来了:

代理怎么告诉滚动视图呢?—— 协议

协议的特点:

  • 只是定义方法,不负责实现
  • <遵守> 协议方法的对象负责实现协议方法
  • 可以给 <遵守> 协议方法的对象发送消息
  • 定义协议,新建 .h 文件 CZScrollViewDelegate.h
  • 编写以下代码定义协议方法
#import <UIKit/UIKit.h>/** CZScrollViewDelegate 定义协议 <NSObject> 表示任何一个 NSObject 都可以遵守协议 */@protocol CZScrollViewDelegate <NSObject>- (UIView *)要缩放的视图;@end
  • CZScrollView.h 导入头文件
#import "CZScrollViewDelegate.h"
  • 修改 delegate 属性的描述,指定代理遵守协议
@property (nonatomic, weak) id<CZScrollViewDelegate> delegate;
  • 实现按钮监听方法
#pragma mark - 监听方法- (void)缩放给定的视图 {    // 1. 让代理告诉我来缩放谁    UIView *v = [_delegate 要缩放的视图];    // 2. 缩放视图    CGFloat scale = 0.9;    v.transform = CGAffineTransformScale(v.transform, scale, scale);}

代码实现至此,代码结构图如下:


第二步 —— 视图控制器
  • 添加图像素材 003.png
  • 修改 setupUI 方法给 滚动视图添加 UIImageView
// 给 scrollView 添加图像UIImage *image = [UIImage imageNamed:@"003"];UIImageView *iv = [[UIImageView alloc] initWithFrame:sv.bounds];iv.image = image;[sv insertSubview:iv atIndex:0];
  • 设置 滚动视图 的代理
// 设置 scrollView 的代理 - 想知道缩放谁吗?问我sv.delegate = self;

出现警告信息

Assigning to 'id' from incompatible type 'ViewController *const __strong'ViewController 没有遵守 CZScrollViewDelegate 协议

此事运行程序会崩溃,崩溃原因是:

-[ViewController 要缩放的视图]: unrecognized selector sent to instance 0x7fb9fad4be20

  • 在私有扩展遵守协议
@interface ViewController () <CZScrollViewDelegate>

细节:因为 CZScrollView.h 已经 #importCZScrollViewDelegate.h,所以在视图控制器中不需要再次#import

  • 实现协议方法
#pragma mark - CZScrollViewDelegate- (UIView *)要缩放的视图 {    return nil;}

再次运行,因为控制器已经实现了协议方法,所以不会再崩溃了

  • 定义属性记录图像视图
@property (nonatomic, weak) UIImageView *imageView;
  • setupUI 方法中记录图像视图
_imageView = iv;
  • 修改协议方法
#pragma mark - CZScrollViewDelegate- (UIView *)要缩放的视图 {    return _imageView;}

运行程序,搞定!:D,示意图如下


代理属性为什么要是弱引用?
  • 为了避免循环引用
    • 因为视图控制器强引用 view
    • view 强引用 subviews
    • 在通过 addSubview 方法添加子视图的时候,subviews 数组会对 scrollview 强引用
    • 如果 scrollview 对 delegate 强引用,那么当 sv.delegate = self; 时,相当于 scrollView 对视图控制器做了强引用
0 0
原创粉丝点击