欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

华山论剑之浅谈iOS的 target - action设计模式 和 代理模式 以及Bolck

程序员文章站 2024-03-22 08:05:58
...

当我们觉得一件事情是理所当然的时候,那正是我们失去它的时候.

target - action设计模式 和 代理模式 以及Bolck 不管是哪一个,都是我们在编程过程中比较常用的,但是真正有多少人还记得他们的实现原理的?今天我就浅谈一下target - action设计模式 和 代理模式 以及Bolck 这三个模块.在谈之前,我们先看一张搞笑的图片,让我们对三种模式有个初步的了解.

华山论剑之浅谈iOS的 target - action设计模式 和 代理模式 以及Bolck
设计模式


target - action设计模式


target - action设计模式 是一种比较常见的设计模式,比如我们在用button的时候,给button添加一个事件,我们就用到了target - action设计模式.现在我们就用target - action设计模式 做一个button,还原button的设计原理,当然了 我们还要加上tap手势.

现在我们在我们的.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

在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];
     
    }
    
}


代理模式


代理模式是什么?代理模式就是制定一个执行者去做某件事情,是不是觉得跟target - action设计模式很相似?我们现在就对代理模式进行一下代码的尝试.

在.h文件中我们首先要声明一个协议,然后在协议中声明我们要实现的代理方法,然后我们要在这个类的声明一个代理的属性,这里我就做一个当我们点击我们的视图的时候就会改变的颜色.

#import <UIKit/UIKit.h>

@protocol TouchViewDelegate <NSObject>

-(void)changeViewColor:(UIColor *)color;

@end


@interface TouchView : UIView

//声明一个代理,这个代理遵守TouchViewDelegate协议,
@property(nonatomic,assign)id<TouchViewDelegate> delegate;

@end

在.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

然后我们看一下在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



Bolck


Bolck块在我们的编程过程中也是很常用的,它叫匿名函数,其实它不是函数,而是一个数据类型,就如同int,char一样,但是要给Bolck赋的值却是一个函数!!Bolck保存的是一个函数..当我们不懂的时候,是可以这样的理解的..当然,我们使用Bolck和代理模式很多时候是用于做传值使用的.

现在我们做一个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传值的实现原理.

华山论剑之浅谈iOS的 target - action设计模式 和 代理模式 以及Bolck
block设计模式


target - action设计模式 和 代理模式 以及Bolck在编程过程中用的比较多,这里就做一下简单的介绍.希望大家能够喜欢这篇文章.