美文网首页
iOS之block的使用

iOS之block的使用

作者: 长不大的帅小伙 | 来源:发表于2016-09-30 19:12 被阅读81次

    这篇文章主要的目的是介绍一下block如何使用,希望对大家有所帮助,同时也方便自己记忆。

    block基础知识

    1. 下面通过实例由浅入深逐步分析:
    • 例1:
      一个最简单的block如下:
    ^{ 
       // block implementation here
    }
    
    • 例2:
      从下面这个例子看出block其实就是一个值,可以把他当成int,float,或者OC对象,赋值给变量。只不过这个变量看起来有点奇怪。
    void (^blockName)() = ^{ // block implementation here};
    
    • 例3:
      这个例子中定义的block返回值是int,参数是a和b。
    int (^addBlock)(int a, int b) = ^{ 
        return a + b;
    };
    int add = addBlock(2, 5); // add == 7
    
    • 例4:
      block有个强大之处:在声明它的范围里,所有变量都可以为其所捕获,也就是说那个范围里的全部变量,在block中依然可用
    int c = 5;
    // __block int c = 5; // 加__block修饰,在下面的块中才可以修改c的值,否则只能访问不能修改
    int (^addBlock)(int a, int b) = ^{ 
        // c = 3;  
        return a + b + c; // 依然可以访问c
    };
    int add = addBlock(2, 5);
    
    2. block闭包写法

    如果你有过类似js、lua等脚本语言的编程经验,那么你应该对闭包这个概念比较熟悉,IOS中的block就可以实现闭包,使代码结构更巧妙灵活。

    - (void)functionAA {
        int a = 10;
        if (flag) {
            NSLog(@"do some thing1 with a %@", @(a));
            NSLog(@"do some thing2 with a %@", @(a));
        } else {
            if (flag1) {
                NSLog(@"do some thing1 with a %@", @(a));
                NSLog(@"do some thing2 with a %@", @(a));
            } else {
                NSLog(@"do some thing3");
            }      
        }
    }
    

    通过上面这段代码不难看出flag和flag1中要做的事其实是一样的,然而有什么办法能让他们复用起来,使代码结构更简洁,相信很多人想到可单独抽一个私有方法出来,这的确是一个办法,不过这样有个麻烦的事,需要把参数传递到私有方法,下面对这段方法进行改造:

    - (void)functionAA {
        int a = 10;
        void (^doSomeThingBlock)() = ^{
            NSLog(@"do some thing1 with a %@", @(a));
            NSLog(@"do some thing2 with a %@", @(a));
        };
        if (flag) {
            doSomeThingBlock();
        } else {
            if (flag1) {
                doSomeThingBlock();
            } else {
                NSLog(@"do some thing3");
            }      
        }
    }
    

    对比这两段代码,这里的doSomeThingBlock就是闭包的写法,而且doSomeThingBlock可以访问到变量a,如果使用抽出私有方法的方式就需要把变量a传给私有方法。

    3. 如何为常用的块类型创建typedef

    先看一个例子:

    // 原来的写法
    int (^JLSomeBlock)(BOOL flag, int value) = ^{};
    
    // 新写法
    typedef int (^JLSomeBlock)(BOOL flag, int value);
    JLSomeBlock block = ^(BOOL flag, int value){};
    

    对于一些常用的block,我们可以用typedef定义,下面再举个例子进行分析:

    - (void)doFuncWithCallBackBlock:(void (^)(int a, int b))block;
    
    // 采用声明block的方式
    typedef void(^callBackBlock)(int a, int b);
    - (void)doFuncWithCallBackBlock:(callBackBlock)block;
    

    设想一下,当有特殊要求要给doFuncWithCallBackBlock方法的block参数加一个参数NSData,如果采用的是第一种方式,这个时候就痛苦了,需要在项目中全局去查收所有doFuncWithCallBackBlock,然后进行逐个修改,那么如果用的是第二种方式,只需要将声明部分修改成typedef void(^callBackBlock)(int a, int b, NSData *data);就搞定了。具体用哪种方式,做项目的时候多考虑考虑,慢慢就会体会的更深了,从而选择出最佳方案。

    4. block和delegate做个简单比较

    在IOS开发中,动态代理设计模式无处不在,如:tableView、collectionView等各种控件,苹果都会封装好,并且通过delegate的方式留下开口,让使用者去实现它的delegate中定义的方法,苹果会在它封装的底层代码中去调用我们实现的方法,拓展性极强。block还有个强大的用处,就是他也可以充分的体现这种思想。

    • delegate的方式
    /** 代理方式的代码片段 */
    - (void)fetchData1 {
        self.fetcher1.delegate = self;
        [self.fetcher1 start]; // 会在start方法中调用代理方法
    }
    - (void)fetchData2 {
        self.fetcher2.delegate = self;
        [self.fetcher2 start]; // 会在start方法中调用代理方法
    }
    
    // 代理方法
    - (void)dataFetcher:(JLDataFetcher *)fetcher didFinishWithData:(NSData *data)
    {
        if(fetcher == self.fetcher1){
            // do something
            self.data = data;
        } else if(fetcher == self.fetcher2){
            // do something
            self.data = data;
        }
    }
    

    从上面代码片段可以看出,一旦情况很多种的时候,代理方法会越来越长,那么如果说采用block的方式会有什么效果呢?请看事例:

    • block方式
    - (void)fetchData1 {
        [self.fetcher1 startWithCompletionHandler:^(NSData *data){
            // do something
            self.data = data;
        }];
    }
    - (void)fetchData2 {
        [self.fetcher2 startWithCompletionHandler:^(NSData *data){
            // do something
            self.data = data;
        }];
    }
    

    这里的block会在startWithCompletionHandler方法中被调用,和上面代理的方式会在start方法中调用代理方法是一个道理,这样的好处在于回调的逻辑可以各自分开处理,具体更多的好处还是自己多多体会吧。

    相关文章

      网友评论

          本文标题:iOS之block的使用

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