(IOS)Block

2018-12-28  本文已影响0人  rightmost

1、Block的声明

格式:

返回值 (^Block名称) (参数类型);

举例:

    //无参无返回值的Block

    void (^Block01)();

    //有参无返回值的Block

    void (^Block02)(int);

    //无参有返回值的Block

    int (^Blcok03)();

    //有参有返回值的Block

    int (^Blcok04)(NSString*, NSString *);

2、Block的定义

格式:

  返回值类型 (^Block名称) (参数类型) = ^(参数) {

        代码体

    };

举例:

//定义无参无返回值的Block

void (^Block01)() = ^(){

        NSLog(@"无参无返回值的Block");

    };

//定义有参无返回值的Block

void (^Block02)(NSString *) = ^(NSString * name) {

        NSLog(@"%@",name);

    };

//定义有返回值无参Block(如果没有参数,=后面()可以省略)

int (^Block03) () = ^() { 

        return 88;

    };

//定义有参有返回值的Block

int (^Block04)(int,int) = ^(int a, int b) {

        return a + b;

    };

Tips:快速生成Block定义:在方法体内输入inlineBlock,选中提示,就会自动生成

3、Block的调用

    //调用无参无返回值Block

    Block01();

    //调用有参无返回值Block

    Block02(@"lee");

    //调用无参有返回值Block

    int a = Block03();

    //调用有参有返回值Block

    int b = Block04(66,88);

4、Block使用场景

传值,回调

作为方法参数使用

注意:Block当做参数来使用,并不是马上调用;要在Block做什么事情由外部决定,什么时候做事情由方法内部决定。举个比较常用的例子:

    self.view.transform = CGAffineTransformMakeScale(0.5, 0.5);

    [UIView animateWithDuration:1 animations:^{

        [self.view layoutIfNeeded];

    }];

作为方法返回值使用(多用于框架封装)

Blcok作为返回值使用多用于框架封装,比较典型的一个例子就是:Masnoary, 最大的特点就是可以很方便的使用点语法,也就是链式编程。

5、Block内存管理

如果Block没有引用外部局部变量,Block就保存在内存的全局区

只要Block引用了外部局部变量,Block就保存在堆内存中

Block最好不要使用copy,应该使用strong

6、解决循环引用

Block循环引用原因:Block会对里面所有外部局部变量(强指针变量)进行一次强引用,从而导致循环引用。

//需要将外部的强指针变量弱化__weak typeof(self) weakSelf = self;

_block = ^{

        NSLog(@"%@",weakSelf);

    };

如果Block里面有非即时操作(延时操作),由于Block内部是弱指针指向,当{}结束之后就被销毁,从而导致延时操作没办法执行,需要在Block内部将弱化的指针再变为强指针

__weak typeof(self) weakSelf = self;

_block = ^{

        NSLog(@"%@",weakSelf);

      //将已经弱化的self指针,转换为强指针以便进行延时操作,否则就执行不到延时操作

        __strong typeof(weakSelf) strongSelf = weakSelf;

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            NSLog(@"%@",strongSelf);

        });

    };

当 block 本身不被 self 持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用 weak self 了。最常见的代码就是 UIView 的动画代码,我们在使用 UIView 的 animateWithDuration:animations 方法 做动画的时候,并不需要使用 weak self,因为引用持有关系是:

UIView 的某个负责动画的对象持有了 block

block 持有了 self

因为 self 并不持有 block,所以就没有循环引用产生,因为就不需要使用 weak self 了。

[UIView animateWithDuration:0.2 animations:^{

    self.alpha = 1;

}];

Tips:以下4种情况打印结果分别是多少?

情况1:

- (void)viewDidLoad

{

    [super viewDidLoad];

    int a = 3;

    void (^ block)() = ^{

        NSLog(@"%d",a); 

    };

    a = 5;

    block();

}

情况2:

- (void)viewDidLoad

{

    [super viewDidLoad];

  static int a = 3;                    ***区别点:静态变量***

    void (^ block)() = ^{

        NSLog(@"%d",a); 

    };

    a = 5;

    block();

}

情况3:

- (void)viewDidLoad

{

    [super viewDidLoad];

  __block int a = 3;                    ***区别点:被__block修饰***

    void (^ block)() = ^{

        NSLog(@"%d",a); 

    };

    a = 5;

    block();

}

情况4:

__block int a = 3;                      ***区别点:全局变量***

- (void)viewDidLoad

{

    [super viewDidLoad];

    void (^ block)() = ^{

        NSLog(@"%d",a); 

    };

    a = 5;

    block();

}

总结:

如果是局部变量(情况1),Block是值传递,打印结果是3;

如果是静态变量(情况2),全局变量(情况4),被__block修饰(情况3),Block是指针传递(地址传递),打印结果是5;

上一篇下一篇

猜你喜欢

热点阅读