zoukankan      html  css  js  c++  java
  • iOS之Block

    iOS中的Block机制,可以简化程序,实现回调功能。跟C语言中的函数指针类似。可以通过传递Block实现函数的回调处理。

    简单地例子:

      定义一个block

      int(^myblock)(int a, int b);

      解释:定义了一个block,名称是myblock(类似函数指针),它的返回类型是int,传入2个int型的a,b的参数。

      

      定义函数指针具体要做的内容。(函数体)

      myblock = ^(int a, int b){

        retrun a+b;

      };

      解释:定义了myblock的具体功能,根据传入的2个int型参数,求和返回。

    再看一个复杂一点的对象参数block。

      这个block完成的功能是:连接2个字符串。

      //简单实例3

        NSString*(^concatString)(NSString *s1,NSString *s2) = ^(NSString *s1, NSString *s2){

            return [s1 stringByAppendingString:s2];

        };

        

        NSLog(@"%@",concatString(@"hello",@" world"));      //打印:hello world

     

    block作为函数的参数使用:

      -(void)blockParams:(int(^)(int value)) my_block;       //参数是一个block,block的返回值是int,它有一个int的参数。

      实现代码:

      -(void)blockParams:(int (^)(int))my_block{

          my_block(4);

      }

     

    在程序中用到更多地关于block的方式,是block回调。就是将block的地址传递到另一个界面,在另一个界面处理好相关数据后,需要回传一些数据给

    前一个界面,然后让前一个界面去处理。这样的业务逻辑很常见。

    举个栗子:

    用户注册时,进行地址的选择,需要从当前A界面跳转到地址列表中(另一个界面B),选择好自己的地址后,需要将地址回传到第一个界面A去处理。

    这个时候可以用block来完成这个操作。当然。使用代理protocal也是可以做到的。这里讨论block。

    具体写法如下:

    在B中定义一个block。

    这里使用typedef关键字去建立。typedef void(^myBlock)(int a, int b);

    B界面的.h文件如下:

    1 #import <UIKit/UIKit.h>
    2 
    3 typedef void(^myBlock)(int a, int b);
    4 
    5 @interface SecondViewController : UIViewController
    6 
    7 -(void)getTwoNumber:(myBlock) block;
    8 
    9 @end

    B界面的.m文件如下:

     1 #import "SecondViewController.h"
     2 
     3 @implementation SecondViewController
     4 
     5 - (void)viewDidLoad {
     6     [super viewDidLoad];
     7     // Do any additional setup after loading the view from its nib.
     8     self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
     9 }
    10 
    11 -(void)getTwoNumber:(myBlock) block{
    12     //假设此处有复杂的操作,最终获得2个值,x,y。
    13     int x = 12;
    14     int y = 13;
    15     
    16     //将x,y回传调用A界面定义的block方法去处理。
    17     block(x, y);
    18     
    19 }
    20 
    21 - (void)didReceiveMemoryWarning {
    22     [super didReceiveMemoryWarning];
    23     // Dispose of any resources that can be recreated.
    24 }
    25 
    26 @end

    B界面已经全部写好了,现在需要在A界面去调用B界面的方法。写法如下:

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

    [svc getTwoNumber:^(int a, int b) {

      NSLog(@"value a,b : %d,%d",a,b);

    }];

    [self.navigationController pushViewController:svc animated:YES];

    这样就实现了回调。其实上面在A界面调用svc的getTwoNumber的方法时,就已经回调了。

    其实应该在B未来某个不确定的时间里,去回调block。怎么做。

    在B中声明一个b_myblock,保存住A传过来的block地址就可以了。代码如下:

     1 #import <UIKit/UIKit.h>
     2 
     3 typedef void(^myBlock)(int a, int b);
     4 
     5 @interface SecondViewController : UIViewController
     6 
     7 @property (strong, nonatomic) myBlock b_myblock;
     8 
     9 -(void)getTwoNumber:(myBlock) block;
    10 
    11 @end

    在B界面中,定义了一个按钮,添加了点击事件。点击时,就会传入参数,回调A中的block,在A中去处理参数。

     1 #import "SecondViewController.h"
     2 
     3 @implementation SecondViewController
     4 
     5 - (void)viewDidLoad {
     6     [super viewDidLoad];
     7     // Do any additional setup after loading the view from its nib.
     8     self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
     9 }
    10 
    11 -(void)getTwoNumber:(myBlock) block{
    12     _b_myblock = block;
    13 }
    14 - (IBAction)buttonClick:(id)sender {
    15     int x = 12;
    16     int y = 13;
    17     
    18     //将x,y回传调用A界面定义的block方法去处理。
    19     _b_myblock(x, y);
    20 }
    21 
    22 - (void)didReceiveMemoryWarning {
    23     [super didReceiveMemoryWarning];
    24     // Dispose of any resources that can be recreated.
    25 }
    26 
    27 @end

    关于__block关键字的使用与解释:

    什么情况下使用__block关键字?

    比对下面2段代码:

    1 //    ========================
    2     NSString* prefix_string = @"HEAD";
    3     NSString*(^concatString)(NSString* foot);
    4     concatString = ^NSString *(NSString *foot){
    5         return [prefix_string stringByAppendingString:foot];
    6     };
    7     concatString(@"_FOOT");
    8 //    ========================
    1 //    ========================
    2     __block NSString* prefix_string = @"HEAD";
    3     NSString*(^concatString)(NSString* foot);
    4     concatString = ^NSString *(NSString *foot){
    5         prefix_string = @"NEW_HEAD";
    6         return [prefix_string stringByAppendingString:foot];
    7     };
    8     concatString(@"_FOOT");
    9 //    ========================

    上面的代码说明什么情况下使用__block关键字。

    在block内部使用非局部变量prefix_string时,如果不对prefix_string本身做修改的话,是不用加上__block关键字的。

    如果要在block内部修改非局部变量,请务必加上__block。如果不加上,编译器也会报错的。

    当一个非局部变量声明成了__block,在block体内操作这个非局部变量,对外面的这个非局部变量同样产生影响,改变它的值。

    当没有使用__block定义非局部变量时,在block体中,就会产生一个非局部变量的副本,此时,block形成了闭包。

    在block外对非局部变量操作时,不会影响block里面的值。

    如果加了__block,此时对外部的非局部变量操作,会同时影响block内的变量值。

    测试代码: 

    第一段代码输出是:

    RED_FOOT    RED

    BLUE_FOOT    BLUE

    第二段代码输出是:

    RED_FOOT    RED

    RED_FOOT    BLUE

     1 //    ========================
     2     __block NSString* prefix_string = @"RED";
     3     NSString*(^concatString)(NSString* foot);
     4     concatString = ^NSString *(NSString *foot){
     5         return [prefix_string stringByAppendingString:foot];
     6     };
     7     
     8     NSLog(@"%@    %@",concatString(@"_FOOT"), prefix_string);
     9     prefix_string = @"BLUE";
    10     NSLog(@"%@    %@",concatString(@"_FOOT"), prefix_string);
    11 
    12 //    ========================
     1 //    ========================
     2     NSString* prefix_string = @"RED";
     3     NSString*(^concatString)(NSString* foot);
     4     concatString = ^NSString *(NSString *foot){
     5         return [prefix_string stringByAppendingString:foot];
     6     };
     7     
     8     NSLog(@"%@    %@",concatString(@"_FOOT"), prefix_string);
     9     prefix_string = @"BLUE";
    10     NSLog(@"%@    %@",concatString(@"_FOOT"), prefix_string);
    11 //    ========================

    由上面可以很好的理解__block的作用,以及程序闭包,对upvalue(非block内部的局部变量)值的副本建立。

    ====================华丽丽的分割线=========================

    总结:block将函数进行封装,并且可以通过传递block的引用的方式,大大的便利了程序的开发。

    可以在程序的任意地方,使用block来完成回调处理事件。而block的闭包机制,也可以给block的安全性

    带来极大的便利。不会因为外部对非局部变量的操作,引起block内部的错乱。block类似于函数指针,

    对block的合理利用,很大程度上的提高程序的可读性。

  • 相关阅读:
    visual studio disable git
    app常见性能测试点
    App测试流程及测试点(个人整理版)
    APP测试要点
    APP端测试常见的功能点
    一文搞懂性能测试常见指标
    为什么会有生产bug?
    线上出了bug,是谁的责任?
    生产上线发现重大Bug的思考
    项目上线后出现Bug,该如何处理?
  • 原文地址:https://www.cnblogs.com/vokie/p/4868625.html
Copyright © 2011-2022 走看看