【Block回调】用于参数传递很不错的例子。

Block回调




我们在开发中常常用到函数回调,你可以用通知来代替回调,但是大多数时候回调还是比通知方便。


  A 简单两个界面之间的传值


  1 在A界面 一个 label 一个 button

  2 点击button跳转到B界面 

  3 在B界面 的textField输入内容 ,单击按钮返回。并将值传递给A界面

  4 A界面的label接受传递的值 并且显示。


我用的代码布局还需要在AppDelegate.h设置根控制器,我就不写了太简单了。这是其他的代码直接复制即可。


ViewController.h


#import "ViewController.h"

#import "SecondViewController.h"

@interface ViewController ()

@property (nonatomic,strong) UILabel *nameLabel;

@end


@implementation ViewController


- (void)viewDidLoad

{

    [super viewDidLoad];


    //设置跳转按钮

    UIButton *btn=[[UIButton alloc]initWithFrame:CGRectMake(20, 180, 130, 50)];

    [btn setTitle:@"跳转" forState:UIControlStateNormal];

    [btn setTintColor:[UIColor orangeColor]];

    btn.backgroundColor=[UIColor blackColor];

    [btn addTarget:self action:@selector(clickAction) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:btn];

  

    self.nameLabel=[[UILabel alloc] initWithFrame:CGRectMake(20, 80, 130, 50)];

    self.nameLabel.backgroundColor=[UIColor orangeColor];

    [self.view addSubview:self.nameLabel];

    

}


- (void)clickAction

{

    SecondViewController *one=[[SecondViewController alloc]init];

    [self presentViewController:one animated:YES completion:nil];


    

    one.block=^(NSString *str){ self.nameLabel.text=str; };

}


SecondViewController.h


#import <UIKit/UIKit.h>


@interface SecondViewController : UIViewController


typedef void(^ablock)(NSString *);


@property (nonatomic,copy) ablock block;



@end



SecondViewController.m


#import "SecondViewController.h"


@interface SecondViewController ()


@property (strong, nonatomicUITextField *nameTextField;

@property (nonatomic,strong) UIButton *btn;

@end


@implementation SecondViewController


- (void)viewDidLoad

{

    [super viewDidLoad];


    //设置跳转按钮

    UIButton *btn=[[UIButton alloc]initWithFrame:CGRectMake(20, 180, 130, 50)];

    [btn setTitle:@"跳转" forState:UIControlStateNormal];

    [btn setTintColor:[UIColor orangeColor]];

    btn.backgroundColor=[UIColor blackColor];

    [btn addTarget:self action:@selector(clickAction) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:btn];

    self.btn=btn;

    

    

    self.nameTextField=[[UITextField alloc] initWithFrame:CGRectMake(20, 80, 120, 40)];

    self.nameTextField.layer.masksToBounds=YES;

    self.nameTextField.layer.cornerRadius=20;

    [self.view addSubview:self.nameTextField];

}


- (void)clickAction

{

    if ([self notEmpty]) {

        if (self.block) {

            self.block(self.nameTextField.text);

            //返回上一个界面。

            [self dismissViewControllerAnimated:YES completion:nil];

        }

    }else{

        [self showAlert];

    }

}

-(BOOL)notEmpty{

    if ([self.nameTextField.text length] == 0) {

        return NO;

    }

    return YES;

}

-(void)showAlert{

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"请输入名字" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];

    [alert show];

}

@end






 B 下面简单粗暴的来模拟一下回调使用的场景


1我现在在玩手机

2我手机突然没电了

3我让手机开始充电

4充电的时候我很无聊,要去看电视,等到手机充满电之后停止看电视,继续玩手机。

5我开始看电视

6手机充满电了,我听到手机响一下,我不看电视了,开始玩手机。


这个场景中哪里跟回调类似呢?哪里跟通知类似呢?其实我们可以认为手机充好电了通过回调的方式让我继续玩手机,也可以认为手机充好电了通知我可以继续玩手机,然后我主动继续玩手机。这里更像通知不像回调。但是换个思维想,如果手机本身没有回调机制,那他怎么能在恰好手机刚充满的时候响一下呢?


先不纠结这个问题,我们看看如果用block怎样来实现这样一个场景:


我们随便找个控制器写下以下代码:


- (void)viewDidLoad

 {

    [superviewDidLoad];

    NSLog(@"我在玩手机");

    NSLog(@"手机没电了");

    [selfchargeMyIphone];

    NSLog(@"我在看电视");

}

- (void)chargeMyIphone

{

    //主线程休眠10

    [NSThreadsleepForTimeInterval:10];

     NSLog(@"电充好了");


}

注意 这里我用了NSTread sleep,这样会让我的主线程沉睡10秒钟,这个过程中我我真的可以一边看电视一边充电吗?


2015-09-10 15:54:37.719 38-demo-01[2046:113530]我在玩手机

2015-09-10 15:54:37.719 38-demo-01[2046:113530] 手机没电了

2015-09-10 15:54:47.720 38-demo-01[2046:113530] 电充好了

2015-09-10 15:54:47.721 38-demo-01[2046:113530] 我在看电视


所以我们应该让充电的线程和我看电视的线程错开执行!这里我们就不开新线程了,就让他10秒之后再执行吧。模拟下:



- (void)viewDidLoad {

    [superviewDidLoad];

    NSLog(@"我在玩手机");

    NSLog(@"手机没电了");

    [selfperformSelector:@selector(chargeMyIphone)withObject:nilafterDelay:10];

    NSLog(@"我在看电视");

    

}

- (void)chargeMyIphone

{

     NSLog(@"电充好了");

}



2015-09-10 15:53:06.723 38-demo-01[1985:112573] 我在玩手机

2015-09-10 15:53:06.724 38-demo-01[1985:112573] 手机没电了

2015-09-10 15:53:06.724 38-demo-01[1985:112573] 我在看电视

2015-09-10 15:53:16.724 38-demo-01[1985:112573] 电充好了



看起来没多大问题,但是我们还没写完我们的场景呢,我们想充好电之后继续玩手机?所以我们写在哪儿呢?

如果直接放在看电视后面:

NSLog(@"继续玩手机");

我们看看控制台:


2015-09-10 15:57:08.082 38-demo-01[2110:114748]我在玩手机

2015-09-10 15:57:08.083 38-demo-01[2110:114748]手机没电了

2015-09-10 15:57:08.083 38-demo-01[2110:114748]继续玩手机

2015-09-10 15:57:08.083 38-demo-01[2110:114748] 我在看电视

2015-09-10 15:57:18.083 38-demo-01[2110:114748] 电充好了


呵呵!电都没充好,你就直接继续玩了?所以这里应该是电充好以后我们再继续玩手机?


那么该怎么做?我们可以写进充电函数里吗?


- (void)chargeMyIphone

{


     NSLog(@"电充好了");

     NSLog(@"继续玩手机");


}



2015-09-10 15:59:34.257 38-demo-01[2199:116281]我在玩手机

2015-09-10 15:59:34.258 38-demo-01[2199:116281]手机没电了

2015-09-10 15:59:34.258 38-demo-01[2199:116281]我在看电视

2015-09-10 15:59:44.258 38-demo-01[2199:116281]电充好了

2015-09-10 15:59:44.258 38-demo-01[2199:116281]继续玩手机




看起来没多大问题,但是我们想想看,我们把 继续玩手机写在充电 函数的最后,

如果每次冲完电都继续玩手机,这个没什么问题,但是如果每次冲完电不总是玩手机

怎么办呢?如果逛街呢?这样的话,这样写就不对了,我们想让充电函数最后执行的那一行

是可变化的。有很多方式可以做到,但是这里最好的做法肯定是追加一个block替换掉我们写死的那句代码。

也就是在充电前已经安排好一个充电计划,今天充电完继续玩手机,明天改成逛街。

那么每次调用的还是那个充电函数,只是传入的参数不一样而已。

明白这一点就知道block的最终奥义了。改造下这个函数,为它加个包含代码的参数。



-(void)chargeMyIphone:(void(^)(void))finishBlock

{

     NSLog(@"电充好了");

     finishBlock();


}


这个追加的参数就是我们的block,

第一个void表示此block无返回值  ^ 为block type的标志第二个void表示这个block无参数,finishBlock就是它的名字。

无参数无返回值类型的匿名函数

就是我们最简单的block了,他非常方便我们回调。


因为没有返回值,没有参数,就相当于只有内部的可执行代码

而我们讲一个固定的事件用一段代码作为参数传进来,并且一名字()形式来触发它,

那么这个函数的结尾就不会总是玩手机了,可以是任何事情!


- (void)viewDidLoad {

    [superviewDidLoad];

    NSLog(@"我在玩手机");

    NSLog(@"手机没电了);

    [self chargeMyIphone:^{ NSLog(@"出去逛街 "); }];

    NSLog(@"我在看电视");

    

}

-(void)chargeMyIphone:(void(^)(void))finishBlock

{


    double delayInSeconds=10.0;

    dispatch_time_t poptime=dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds *NSEC_PER_SEC));

    dispatch_after(poptime,dispatch_get_main_queue(), ^(void){

        NSLog(@"电充好了");

        finishBlock();


    });

    


}


2015-09-10 16:17:45.872 38-demo-01[2380:124074]我在玩手机

2015-09-10 16:17:45.873 38-demo-01[2380:124074]手机没电了

2015-09-10 16:17:45.873 38-demo-01[2380:124074]我在看电视

2015-09-10 16:17:56.868 38-demo-01[2380:124074]电充好了

2015-09-10 16:17:56.869 38-demo-01[2380:124074]出去逛街 




现在代码的结果非常清晰

充电完成之后 我要去逛街

充电内不需要消耗10秒

充电的充实我可以看电视

充电完成之后 回头来触发我block中设置的出去逛街





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值