iOS之block的使用

2016-09-30  本文已影响81人  长不大的帅小伙

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

block基础知识

1. 下面通过实例由浅入深逐步分析:
^{ 
   // block implementation here
}
void (^blockName)() = ^{ // block implementation here};
int (^addBlock)(int a, int b) = ^{ 
    return a + b;
};
int add = addBlock(2, 5); // add == 7
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还有个强大的用处,就是他也可以充分的体现这种思想。

/** 代理方式的代码片段 */
- (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的方式会有什么效果呢?请看事例:

- (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方法中调用代理方法是一个道理,这样的好处在于回调的逻辑可以各自分开处理,具体更多的好处还是自己多多体会吧。

上一篇 下一篇

猜你喜欢

热点阅读