美文网首页网络百科转载iOS
华山论剑之浅谈iOS的 target - action设计模式

华山论剑之浅谈iOS的 target - action设计模式

作者: 神经骚栋 | 来源:发表于2016-03-07 22:53 被阅读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>

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

相关文章

网友评论

  • 0271fb6f797c:底层,底层,想知道底层到底怎么实现的,用的runtime还是什么,怎么做到的,为什么能监听按钮的点击呢?用runtime动态添加属性还是什么???不懂,求讲解????? :pray:
    神经骚栋:@dong136279559 runloop
  • qazws:Block修饰难道不是一直是copy吗?能strong吗?不怕强引用吗?
    神经骚栋:@sp5 其实我也不是太懂这个强弱引用的问题,但是我知道block使用起来简单,但是注意强弱引用的地方太多了~ :smiley:
    神经骚栋:@sp5 不能呀~因为我是在ARC环境下,系统会自动释放. :smile:
  • 0x7472616d70:在block中,在ViewController.m中,不把OtherViewController声明为属性,直接在touchesBegan方法中实例化对象,是不是就不需要__weak这句话来修饰了?对循环引用不是太理解,望指教。。
    神经骚栋:@修改昵称吗 在我写的block中,弱引用问题不是OtherViewController引起的,而是ViewController引起的.因为现在大部分是使用ARC环境下进行开的,所以对内存管理这块都不太熟悉,如果说你在blcok中直接用self的属性,相当于强引用,当你在释放内存的时候,因为相互持有,所以ViewController是不能被释放的.这算是比较正统的说法吧,如果还有疑问 你就想着这么一句话就行,在block中如果要引用 本身的属性的时候 ,一定要使用弱引用 上面就是 .weak.label.text = string; 这是不是就引用了自己本省的属性了?所以我才用到弱引用.不懂记住就行.主要是现在在MRC环境下开发的人员太少了~ :blush: :blush:
  • 望月Jarvis::+1::+1:好的文章我都喜欢赞一下,今天给你赞两下:joy::joy:
    神经骚栋:@Deanlzwei 谢谢大牛~感谢~哈哈~ :smiley:
    神经骚栋:@Deanlzwei 谢谢,谢谢,其实就说一下实现原理而已~没想到这么多大神来看,让我受宠若惊~ :smile: :smile:
  • a05832db24ea:多谢了,我的那个回调小功能我觉得用block是最简单最自然的
    神经骚栋:@屎壳郎123 我做项目的时候,Swift用的少,多数用的是OC ,不过你没有写协议,那么给block改名字这个需要吧,还有就是self的弱引用也是一个问题,你不写,会造成循环引用不是? 而且我相信 大多数人熟悉代理比熟悉block的实现原理要多得多? :blush: :blush: :blush:
    a05832db24ea:@神经骚栋 我感觉target-action跟代理没太多区别一样。刚才我把回调功能用闭包重新写了,省了几行代码,不需要为一个回调单独定义一个协议了,我是在swift下。
    神经骚栋:@屎壳郎123 恩恩~技术嘛,条条大路通罗马,你觉得什么方法好就用什么方法,没有最好,只有最合适! :smile:
  • STONEsh:形象生动,浅显易懂,赞一个!
    神经骚栋:@STONEsh 谢谢 ~ 谢谢捧场~

本文标题:华山论剑之浅谈iOS的 target - action设计模式

本文链接:https://www.haomeiwen.com/subject/fotzkttx.html