华山论剑之浅谈iOS的 target - action设计模式
2016-03-07 本文已影响1279人
神经骚栋
当我们觉得一件事情是理所当然的时候,那正是我们失去它的时候.
</b>
target - action设计模式 和 代理模式 以及Bolck 不管是哪一个,都是我们在编程过程中比较常用的,但是真正有多少人还记得他们的实现原理的?今天我就浅谈一下target - action设计模式 和 代理模式 以及Bolck 这三个模块.在谈之前,我们先看一张搞笑的图片,让我们对三种模式有个初步的了解.
设计模式</br>
target - action设计模式
target - action设计模式 是一种比较常见的设计模式,比如我们在用button的时候,给button添加一个事件,我们就用到了target - action设计模式.现在我们就用target - action设计模式 做一个button,还原button的设计原理,当然了 我们还要加上tap手势.
</b>
现在我们在我们的.tapView.h中做两个属性 一个target属性,另外一个是action属性,然后声明一个target - action方法.
#import <UIKit/UIKit.h>
@interface TapView : UIView
//目标
@property(weak,nonatomic)id target;
//行为
@property(assign,nonatomic)SEL action;
//自定义方法
-(void)addCustomtarget:(id)target andAction:(SEL)action;
@end
</b>
在tapView.m文件中我们要两个方法进行实现,一个是-(void)addCustomtarget:(id)target andAction:(SEL)action;另外一个就是-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;这个方法就是模拟button功能的方法.原理就是如果有一个执行者和一个执行者能做的方法,那么我们就让执行者执行那个方法.
#import "TapView.h"
@implementation TapView
//自定义方法
-(void)addCustomtarget:(id)target andAction:(SEL)action{
_action = action;
_target = target;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//当视图点击的时候,target去执行action的方法并把自己传过去.
//首先代理不能是空,而且代理(代理是对象!)的类中有方法并且能传出过来.
if (nil != _target && [[_target class] instancesRespondToSelector:_action]) {
[_target performSelector:_action withObject:self];
}
}
</br>
代理模式
代理模式是什么?代理模式就是制定一个执行者去做某件事情,是不是觉得跟target - action设计模式很相似?我们现在就对代理模式进行一下代码的尝试.
</b>
在.h文件中我们首先要声明一个协议,然后在协议中声明我们要实现的代理方法,然后我们要在这个类的声明一个代理的属性,这里我就做一个当我们点击我们的视图的时候就会改变的颜色.
#import <UIKit/UIKit.h>
@protocol TouchViewDelegate <NSObject>
-(void)changeViewColor:(UIColor *)color;
@end
@interface TouchView : UIView
//声明一个代理,这个代理遵守TouchViewDelegate协议,
@property(nonatomic,assign)id<TouchViewDelegate> delegate;
@end
</b>
在.m中,我们要对代理的方法进行调用一下,这里我传的是一个颜色.
#import "TouchView.h"
@implementation TouchView
//我们还是用touchesBegandian
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (nil != self.delegate && [self.delegate respondsToSelector:@selector(changeViewColor:)]) {
//我们传一个颜色到我们的ViewController去.
[self.delegate changeViewColor:[UIColor brownColor]];
}
}
@end
</b>
然后我们看一下在ViewController.m中所要做的操作吧.还记得nil != self.delegate && [self.delegate respondsToSelector:@selector(changeViewColor:)]
这句代码吗?意思还是当我们的代理人存在,并且他有代理方法,那么我们就让代理人实现代理方法.
#import "ViewController.h"
#import "TouchView.h"
//在这里ViewController 要遵守协议....
@interface ViewController ()<TouchViewDelegate>
@property(nonatomic,strong)TouchView *touchView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.touchView = [[TouchView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
self.touchView.backgroundColor = [UIColor redColor];
//指定touchView的代理为ViewController.即为本身~
self.touchView.delegate =self;
[self.view addSubview: self.touchView];
}
-(void)changeViewColor:(UIColor *)color{
//现在参数color是有值的,这是因为在TouchView那个页面传过来的.
self.touchView.backgroundColor = color;
}
@end
</br>
Bolck
Bolck块在我们的编程过程中也是很常用的,它叫匿名函数,其实它不是函数,而是一个数据类型,就如同int,char一样,但是要给Bolck赋的值却是一个函数!!Bolck保存的是一个函数..当我们不懂的时候,是可以这样的理解的..当然,我们使用Bolck和代理模式很多时候是用于做传值使用的.
</br>
现在我们做一个OtherViewController 和ViewController两个控制器界面之间的传值,我们就使用Bolck来完成这件事情 ,首先我们在OtherViewController.h 声明一个Bolck的属性,当然了,我们需要先改一下名字,让我们的Bolck不是那么的难看.
#import <UIKit/UIKit.h>
//给block改名成MyBlock
typedef void(^MyBlock)(NSString *);
@interface OtherViewController : UIViewController
//MRC:block的语义设置是copy,把block从栈区拷贝到堆区.使用完之后,在dealloc内释放
//ARC:语义设置使用strong即可
@property(nonatomic,strong)MyBlock block;
@end
现在在我们的.m中进行如下的操作,我们有个输入框textField,当我们输入完成之后,我们点击一下页面返回到ViewController 然后把值传给ViewController.
#import "OtherViewController.h"
@interface OtherViewController ()
@property(nonatomic,strong)UITextField *textField;
@end
@implementation OtherViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 100, 414, 40)];
self.textField.backgroundColor = [UIColor lightGrayColor];
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview: self.textField];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.block(_textField.text);
[self.navigationController popViewControllerAnimated:YES];
}
@end
我们在ViewController中做了哪些操作呢?如下,我们需要声明一个OtherViewController的属性,然后给OtherViewController对象的block进行赋值.然后就是push页面了~
#import "ViewController.h"
#import "OtherViewController.h"
@interface ViewController ()
@property(nonatomic,strong)OtherViewController *otherVC;
@property(nonatomic,strong)UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
self.view.backgroundColor = [UIColor whiteColor];
self.label = [[UILabel alloc]initWithFrame:CGRectMake(0, 100, 414, 40)];
self.label.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.label];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.otherVC = [[OtherViewController alloc]init];
__weak typeof(self)weak = self;
//给block赋值~
self.otherVC.block = ^(NSString *string){
weak.label.text = string;
};
[self.navigationController pushViewController:_otherVC animated:YES];
}
@end
现在我们用图说明一下block传值的实现原理.
block设计模式</br>
</br>