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

来源:互联网 发布:免费网络直播加速器 编辑:程序博客网 时间:2024/05/16 03:26

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"

@interfaceViewController ()

@property (nonatomic,strong)UILabel *nameLabel;

@end


@implementation ViewController


- (void)viewDidLoad

{

    [superviewDidLoad];


    //设置跳转按钮

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

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

    [btn setTintColor:[UIColororangeColor]];

    btn.backgroundColor=[UIColorblackColor];

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

    [self.viewaddSubview:btn];

  

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

    self.nameLabel.backgroundColor=[UIColororangeColor];

    [self.viewaddSubview:self.nameLabel];

    

}


- (void)clickAction

{

    SecondViewController *one=[[SecondViewControlleralloc]init];

    [selfpresentViewController:one animated:YEScompletion: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"


@interfaceSecondViewController ()


@property (strong,nonatomicUITextField *nameTextField;

@property (nonatomic,strong)UIButton *btn;

@end


@implementation SecondViewController


- (void)viewDidLoad

{

    [superviewDidLoad];


    //设置跳转按钮

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

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

    [btn setTintColor:[UIColororangeColor]];

    btn.backgroundColor=[UIColorblackColor];

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

    [self.viewaddSubview:btn];

    self.btn=btn;

    

    

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

    self.nameTextField.layer.masksToBounds=YES;

    self.nameTextField.layer.cornerRadius=20;

    [self.viewaddSubview:self.nameTextField];

}


- (void)clickAction

{

    if ([selfnotEmpty]) {

        if (self.block) {

            self.block(self.nameTextField.text);

            //返回上一个界面。

            [selfdismissViewControllerAnimated:YEScompletion:nil];

        }

    }else{

        [self showAlert];

    }

}

-(BOOL)notEmpty{

    if ([self.nameTextField.textlength] == 0) {

        returnNO;

    }

    returnYES;

}

-(void)showAlert{

    UIAlertView *alert = [[UIAlertViewalloc] initWithTitle:@"提示"message:@"请输入名字"delegate:selfcancelButtonTitle:@"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 0
原创粉丝点击