target/action 设计模式
UIButton继承了它的父类UIControl中的如下所示方法:
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
由于UIView UILabel UIImageView 并不是继承于UIControl 所以它们无法直接使用上式方法
但是 它们都有交互属性userInteractionEnabled
(UILabel UIImageView 默认时关的)因此可以通过某种方法模仿UIButton的上式方法
target/action 设计模式便是其中的一种方式
实现步骤:
1.新建一个类ButtonView(也可以是UILabel UIImageView的子类)
2.在.h
中声明两个属性target 和 action
@property (nonatomic, retain) id target;
@property (nonatomic, assign) SEL action;
3.重写初始化方法(需进行声明)
- (instancetype)initWithFrame:(CGRect)frame target:(id)target action:(SEL)action
{
self = [super initWithFrame:frame];
if (self) {
// 初始化时 对属性 进行赋值
self.target = target;
self.action = action;
}
return self;
}
4.在touchEnded方法中实现一个方法(为满足MVC模式 此方法并没有逻辑)
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// NSLog(@"点击");
// 使用self.target对象调用 action
// 让一个对象 去调用这个对象类里的方法
// Object 可携带的参数
[self.target performSelector:self.action withObject:self];
}
5.在根视图控制器上创建ButtonView的实例对象 并添加到self.view上
- (void)viewDidLoad {
[super viewDidLoad];
ButtonView *buttonView = [[ButtonView alloc] initWithFrame:CGRectMake(100, 100, 100, 100) target:self action:@selector(buttonViewClick:)];
buttonView.backgroundColor = [UIColor brownColor];
[self.view addSubview:buttonView];
[buttonView release];
}
6.在controller类中实现触摸结束后需要控制器实现的方法(这个方法才是真正的逻辑方法)
- (void)buttonViewClick:(ButtonView *)buttonView
{
buttonView.backgroundColor = [UIColor redColor];
}
代理设计模式
1.创建协议: 将协议创建在ButtonImageView类里
2.在协议中声明需要代理实现的方法
#import <UIKit/UIKit.h>
// 由于ButtonImageView的interface在下面 在写捕获点击事件方法时还不存在此类 因此需要用关键词@class
@class ButtonImageView;
// 创建一个协议
@protocol ButtonImageViewDelegate <NSObject>
// 捕获点击事件
- (void)buttonImageViewClick:(ButtonImageView *)buttonImageView;
@end
@interface ButtonImageView : UIImageView
3.遵守协议
不管是代理它本身的类 还是需要代理完成方法的ButtonImageView类 都需要引入协议头文件
由于协议创建在了ButtonImageView类中 所以ButtonImageView类不需要引入头文件 而他的代理 也就是它对
应的试图控制器 需要引入ButtonImageView.h头文件
引入头文件后需要在继承的父类后面引入协议
#import <UIKit/UIKit.h>
#import "ButtonImageView.h"
@interface RootViewController : UIViewController<UITextFieldDelegate, ButtonImageViewDelegate>
@end
4.设置代理
// 添加代理属性
// 面试题 代理属性 为什么要声明成assign
// 防止循环引用 从而造成的内存泄露
/*
buttonImageView.delegate = self;
self 之前alloc一次 引用计数加1
如果delegate是retain的话
setter以后self 引用计数再加1
有alloc就release 即使release了self 引用计数还有1 不能触发dealloc方法
*/
@property (nonatomic, assign) id <ButtonImageViewDelegate> delegate;
@end
5.让代理帮助实现touch中的方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// 让代理去干活
// 让代理 去调用代理方法
if ([_delegate respondsToSelector:@selector(buttonImageViewClick:)]) {
[_delegate buttonImageViewClick:self];
}
}
6.实现协议方法
在代理中 也就是试图控制器中创建ButtonImageView的对象 并且添加到self.view上 设置好它的代理 并打开
userInteractionEnabled属性
- (void)viewDidLoad {
[super viewDidLoad];
WeChat *weChatView = [[WeChat alloc] initWithFrame:[UIScreen mainScreen].bounds];
weChatView.passWord.delegate = self;
weChatView.imageView.delegate = self;
weChatView.imageView.userInteractionEnabled = YES;
[self.view addSubview:weChatView];
[weChatView release];
// 需求 点击imageView 实现换背景颜色 并且遵循MVC设计模式
}
// 实现协议中的方法
// 不管是target/Action设计模式 还是 代理设计模式
// 还是MVC 设计模式 中心只有一个 解耦 提高代码的复用性
- (void)buttonImageViewClick:(ButtonImageView *)buttonImageView
{
buttonImageView.backgroundColor = [UIColor redColor];
}